zoukankan      html  css  js  c++  java
  • leetcode刷题 209~

    题目209题

    长度最小的子数组

    给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

    示例:

    输入:s = 7, nums = [2,3,1,2,4,3]
    输出:2
    解释:子数组 [4,3] 是该条件下的长度最小的子数组。

    思路

    双指针法

    实现

    class Solution:
        def minSubArrayLen(self, s: int, nums: List[int]) -> int:
            if not nums:
                return 0
            left,right = 0,0
            result = len(nums) + 1
            temp = 0
            while right < len(nums):
                temp += nums[right]
                while temp >= s:
                    result = min(result, right-left+1)
                    temp -= nums[left]
                    left += 1
                right += 1
            return 0 if result == len(nums) + 1 else result

    题目210题

    课程表II

    现在你总共有 n 门课需要选,记为 0 到 n-1。

    在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]

    给定课程总量以及它们的先决条件,返回你为了学完所有课程所安排的学习顺序。

    可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。

    思路

    拓扑排序!

    实现

    class Solution:
        def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
            reverse_post = list()
    
            edges = collections.defaultdict(list)
            length = len(prerequisites)
            flag = True
    
            for info in prerequisites:
                edges[info[0]].append(info[1])
            visited = [False for _ in range(numCourses)]
            on_stack = [False for _ in range(numCourses)]
    
            def dfs(course):
                nonlocal flag
                print(reverse_post)
                on_stack[course] = True
                visited[course] = True
                for pre in edges[course]:
                    if not on_stack[pre]:
                        if not visited[pre]:
                            dfs(pre)
                    else:
                        flag = False
                        return
                on_stack[course] = False
                reverse_post.append(course)
    
            for i in range(numCourses):
                if not flag:
                    return []
                if not visited[i] and flag:
                    dfs(i)
            if flag:
                return reverse_post
            else:
                return []

    题目211题

    添加与搜索单词

    请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。

    实现词典类 WordDictionary :

    WordDictionary() 初始化词典对象
    void addWord(word) 将 word 添加到数据结构中,之后可以对它进行匹配
    bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回  false 。word 中可能包含一些 '.' ,每个 . 都可以表示任何一个字母。

    思路

    字典的初始化与添加操作与前缀树相同,但搜索操作可以利用深度优先遍历完成

    实现

    class Node:
        def __init__(self, val=None ,end = False):
            self.val = val
            self.is_end = end
            self.next = {}
    
    
    class WordDictionary:
    
        def __init__(self):
            """
            Initialize your data structure here.
            """
            self.root = Node()
            
    
    
        def addWord(self, word: str) -> None:
            """
            Adds a word into the data structure.
            """
            node = self.root
            for i in word:
                if i not in node.next:
                    node.next[i] = Node(i)
                node = node.next[i]
            node.is_end = True
    
    
        def search(self, word: str) -> bool:
            """
            Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter.
            """
            return self.__search(self.root, word)
    
        def __search(self, pre, word):
            node = pre
            if not word:
                if node.is_end:
                    return True
                return False
            if word[0] == ".":
                temp = node.next.keys()
                for t in temp:
                    if self.__search(node.next[t],word[1:]):
                        return True
            elif word[0] in node.next.keys():
                return self.__search(node.next[word[0]],word[1:])
            return False

    题目100题

    打家劫舍II

    你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

    给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

    思路

    动态规划,与198题相比,环状排列意味着第一个房子和最后一个房子中只能选择一个偷窃,因此可以把此环状排列房间问题约化为两个单排排列房间子问题。

    在不偷窃第一个房子的情况下(即 nums[1:]),最大金额是 p1
    在不偷窃最后一个房子的情况下(即 nums[:n-1]),最大金额是 p2

    max(p1,p2)则是环状排列的最大金额

    实现

    class Solution:
        def rob(self, nums: List[int]) -> int:
            return max(self.__rob(nums[:-1]),self.__rob(nums[1:])) if len(nums) != 1 else nums[0]
    
        def __rob(self, nums: List[int]) -> int:
            cur, pre = 0, 0
            for num in nums:
                cur, pre = max(pre + num, cur), cur
            return cur

    题目215题

    数组中的第k个最大元素

    在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

    思路

    堆排序

    实现

    class Solution:
        def findKthLargest(self, nums: List[int], k: int) -> int:
            heapSize = len(nums)
            self.buildMaxHeap(nums, heapSize-1)
            cin = 0
            heapSize -= 1
            while cin < k-1:         
                cin +=1
                nums[0],nums[heapSize] = nums[heapSize], nums[0]
                heapSize -= 1
                self.sink(nums, 0, heapSize)
            return nums[0]
    
        def buildMaxHeap(self, nums, Size):
            k = int(Size/2)
            while k >= 0:
                self.sink(nums, k, Size)
                k -= 1
    
        def sink(self, nums, start, end):
            i, j = start, 2*start
            while j <= end:
                if j < end and nums[j] < nums[j+1]:
                    j += 1
                if nums[i] < nums[j]:
                    nums[i], nums[j] = nums[j], nums[i]
                    i = j
                    j = 2 *i
                else:
                    break

    题目216题

    组合总和III

    找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

    说明:

    所有数字都是正整数。
    解集不能包含重复的组合。 

    思路

    深度优先遍历

    实现

    class Solution:
        def combinationSum3(self, k: int, n: int) -> List[List[int]]:
            result = []
            def com(k,n,index,temp):
                if n == 0 and k == 0:
                    result.append(temp)
                if n >= index and k >0:
                    for i in range(index,10):
                        com(k-1,n-i, i+1,temp+[i])
            com(k,n,1,[])
            return result

    题目217题

    存在重复元素

    给定一个整数数组,判断是否存在重复元素。

    如果任意一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。

    思路

    将数组放入一个set中,若set的长度和list长度不同,则重复

    实现

    class Solution:
        def containsDuplicate(self, nums: List[int]) -> bool:
            return not len(nums) == len(set(nums))

    题目219题

    存在重复元素II

    给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。

    思路

    实现

    class Solution:
        def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
            key = dict()
            for num in range(len(nums)):
                if nums[num] not in key.keys():
                    key[nums[num]] = num
                else:
                    if num - key[nums[num]] <=k:
                        return True
                    key[nums[num]] = num
            return False

    题目220题

    存在重复的元素

    在整数数组 nums 中,是否存在两个下标 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值小于等于 t ,且满足 i 和 j 的差的绝对值也小于等于 ķ 。

    如果存在则返回 true,不存在返回 false。

    思路

    桶排序:桶排序是一种把元素分散到不同桶中的排序算法。接着把每个桶再独立地用不同的排序算法进行排序。

    设计一些桶,让他们分别包含区间 ..., [0,t], [t+1, 2t+1], ......,[0,t],[t+1,2t+1],...。我们把桶来当做窗口,于是每次我们只需要检查 xx 所属的那个桶和相邻桶中的元素就可以了。

    实现

    class Solution:
        def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
            key = dict()
            for i in range(len(nums)):
                id = self.__getid(nums[i], t)
                if id in key.keys():
                    return True
                if (id -1) in key.keys() and abs(key[id-1]-nums[i])<=t:
                    return True
                if (id +1) in key.keys() and abs(key[id+1]-nums[i])<=t:
                    return True
                key[id] = nums[i]
                if len(key) > k:
                    del_id = self.__getid(nums[i-k], t)
                    del key[del_id]
            return False
                
            
        def __getid(self, num, t):
            return num//(t+1)

    题目221题

    最大正方形

    在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。

    示例:

    输入:

    1 0 1 0 0
    1 0 1 1 1
    1 1 1 1 1
    1 0 0 1 0

    输出: 4

    思路

    动态规划:用 dp(i, j) 表示以(i,j) 为右下角,且只包含1的正方形的边长最大值。

    dp(i,j)=min(dp(i1,j),dp(i1,j1),dp(i,j1))+1

    实现

    class Solution:
        def maximalSquare(self, matrix: List[List[str]]) -> int:
            if len(matrix) == 0 or len(matrix[0]) == 0:
                return 0
            
            maxSide = 0
            rows, columns = len(matrix), len(matrix[0])
            dp = [[0 for _ in range(columns)] for _ in range(rows)]
            for i in range(rows):
                for j in range(columns):
                    if matrix[i][j] == '1':
                        if i == 0 or j == 0:
                            dp[i][j] = 1
                        else:
                            dp[i][j] = min(dp[i-1][j],dp[i-1][j-1],dp[i][j-1])+1
                        maxSide = max(maxSide, dp[i][j])
            return maxSide*maxSide

    题目222题

    完全二叉树的节点个数

    给出一个完全二叉树,求出该树的节点个数。

    思路

    1. 递归

    2.广度优先遍历

    但前两种方法都没有利用到完全二叉树的特性

    3.二分搜索

    这个问题的实质是最后一层的叶子节点树量

    实现

    1.
    # Definition for a binary tree node.
    # class TreeNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    
    class Solution:
        def countNodes(self, root: TreeNode) -> int:
        return 1 + self.countNodes(root.right) + self.countNodes(root.left) if root else 0
    2.
    class Solution:
        def countNodes(self, root: TreeNode) -> int:
            if not root:
                return 0
            queue = collections.deque()
            queue.append(root)
            result = 0
            while queue:
                node = queue.popleft()
                result += 1
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            return result
    3.
    class Solution:
        def conutlevel(self, node):
            level = 0
            while node.left:
                node = node.left
                level += 1         
            return level

        def exists(self, idx, level, node):
            left, right = 0, 2**level - 1
            for _ in range(level):
                mid = left + (right - left)//2
                if idx <= mid:
                    node = node.left
                    right = mid
                else:
                    node = node.right
                    left = mid + 1
            return node is not None

        def lastlevel(self, level, node):
            left, right = 0, 2**level - 1
            while left <= right:
                mid = left + (right - left)//2
                if self.exists(mid, level, node):
                    left = mid + 1
                else:
                    right = mid - 1
            return left

        def countNodes(self, root: TreeNode) -> int:
            if not root:
                return 0
            level = self.conutlevel(root)
            if level == 0:
                return 1
            last = self.lastlevel(level,root)
            return 2**level - 1 + last

    题目223题

    矩形面积

    在二维平面上计算出两个由直线构成的矩形重叠后形成的总面积。

    思路

    有两种情况:有重叠和无重叠

    计算时将两个矩形面积和减去重叠面积,当重叠部分的边为负数时,取0

    实现

    class Solution:
        def computeArea(self, A: int, B: int, C: int, D: int, E: int, F: int, G: int, H: int) -> int:
            x1 = max(A,E)
            y1 = max(B,F)
            x2 = min(C,G)
            y2 = min(D,H)
            cover = max(0,(x2-x1))* max(0,(y2-y1))
            total =  (C-A)*(D-B) +(G-E)*(H-F)
            return total - cover

    题目225题

    用队列实现栈

    思路实现

    class MyStack:
    
        def __init__(self):
            """
            Initialize your data structure here.
            """
            self.stack = []
    
    
        def push(self, x: int) -> None:
            """
            Push element x onto stack.
            """
            self.stack.append(x)
    
    
        def pop(self) -> int:
            """
            Removes the element on top of the stack and returns that element.
            """
            return self.stack.pop()
    
    
        def top(self) -> int:
            """
            Get the top element.
            """
            return self.stack[-1]
    
    
        def empty(self) -> bool:
            """
            Returns whether the stack is empty.
            """
            return len(self.stack) == 0

    题目227题

    基本计算器

    实现一个基本的计算器来计算一个简单的字符串表达式的值。

    字符串表达式仅包含非负整数,+, - ,*/ 四种运算符和空格  。 整数除法仅保留整数部分。

    思路

    实现

    class Solution:
        def calculate(self, s: str) -> int:
            stack = []
            num = "0123456789"
            op = "+"
            temp = 0
            idx = 0
            for i in range(len(s)):
                wait = s[i]
                if wait.isdigit():
                    temp = temp*10 + int(wait)
                if wait in "+-*/" or i == len(s)-1:
                    if op is "+":
                        stack.append(temp)
                    elif op is "-":
                        stack.append(-temp)
                    elif op is "*":
                        pre = stack.pop()
                        stack.append(pre*temp)
                    elif op is "/":
                        pre = stack.pop()
                        stack.append(int(pre/temp))
                    op = wait
                    temp = 0
            return sum(stack)

    题目228题

    汇总区间

    给定一个无重复元素的有序整数数组 nums 。

    返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表。也就是说,nums 的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于 nums 的数字 x 。

    列表中的每个区间范围 [a,b] 应该按如下格式输出:

    "a->b" ,如果 a != b
    "a" ,如果 a == b

    思路

    双指针

    实现

    class Solution:
        def summaryRanges(self, nums: List[int]) -> List[str]:
            if not nums:
                return []
            left,right = 0, 0
            temp = []
            result = []
            while left<=right and right != len(nums):
                if nums[right] == nums[left] or nums[right] == nums[right-1] + 1:
                    temp.append(str(nums[right]))
                    right += 1
                elif nums[right] > nums[right-1] + 1:
                    if len(temp) > 1:
                        result.append(temp[0]+"->"+temp[-1])
                    else:
                        result.append(temp[0])
                    temp = []
                    left = right
            if len(temp) > 1:
                result.append(temp[0]+"->"+temp[-1])
            else:
                result.append(temp[0])
            return result

    题目229题

    求众数II

    给定一个大小为 n 的数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。

    进阶:尝试设计时间复杂度为 O(n)、空间复杂度为 O(1)的算法解决此问题。

    思路

    利用字典非常容易,但是无法满足空间复杂度为1。因此采用摩尔投票法。

    摩尔投票法分为两个阶段:抵消阶段和计数阶段。

    抵消阶段:两个不同投票进行对坑,并且同时抵消掉各一张票,如果两个投票相同,则累加可抵消的次数;

    计数阶段:在抵消阶段最后得到的抵消计数只要不为 0,那这个候选人是有可能超过一半的票数的,为了验证,则需要遍历一次,统计票数,才可确定。

    摩尔投票法经历两个阶段最多消耗 O(2n) 的时间,也属于 O(n) 的线性时间复杂度,另外空间复杂度也达到常量级。

    实现

    class Solution:
        def majorityElement(self, nums: List[int]) -> List[int]:
            if not nums:
                return []
            n = len(nums)
            cand1, count1 = nums[0], 0
            cand2, count2 = nums[0], 0
            result = []
            for num in nums:
                if cand1 == num:
                    count1 += 1
                    continue
                if cand2 == num: 
                    count2 += 1
                    continue
                if count1 == 0:
                    cand1 = num
                    count1 += 1
                    continue
                if count2 == 0: 
                    cand2 = num
                    count2 += 1
                    continue
                count1 -= 1
                count2 -= 1
            count1, count2 = 0, 0
            for num in nums:
                if num == cand1:
                    count1 += 1
                elif num == cand2:
                    count2 += 1
            if count1 > n/3 :
                result.append(cand1)
            if count2 > n/3:
                result.append(cand2)
            return result

    题目230题

    二叉搜索树中第k小的元素

    给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。

    思路

    深度优先遍历

    实现

    class Solution:
        def kthSmallest(self, root: TreeNode, k: int) -> int:
            
            def dfs(node):
                return dfs(node.left) + [node.val] + dfs(node.right) if node else []
            
            return dfs(root)[k-1]

    题目231题

    2的幂

    给定一个整数,编写一个函数来判断它是否是 2 的幂次方。

    思路

    1. 递归

    2.位运算:

    2 的幂在二进制中是有一个 1 后跟一些 0;不是 2 的幂的二进制中有一个以上的 1

    x & (-x) 将保留最右边的 1。并将其他的位设置为 0。因此判断是否为 2 的幂的关键是:判断 x & (-x) == x

    实现

    1.
    class Solution:
        def isPowerOfTwo(self, n: int) -> bool:
            if n <= 0:
                return False
            elif n == 1:
                return True
            elif n%2 == 0:
                return self.isPowerOfTwo(n/2)
            else:
                return False
    2.
    class Solution(object):
        def isPowerOfTwo(self, n):
            if n == 0:
                return False
            return n & (-n) == n

    题目232题

    用栈实现队列

    使用栈实现队列的下列操作:

    push(x) -- 将一个元素放入队列的尾部。
    pop() -- 从队列首部移除元素。
    peek() -- 返回队列首部的元素。
    empty() -- 返回队列是否为空。

    思路实现

    class MyQueue:
    
        def __init__(self):
            """
            Initialize your data structure here.
            """
            self.s1 = list()
            self.s2 = list()
            self.front = None
    
    
        def push(self, x: int) -> None:
            """
            Push element x to the back of queue.
            """
            if len(self.s1) == 0:
                self.front = x
            self.s1.append(x)
    
        def pop(self) -> int:
            """
            Removes the element from in front of queue and returns that element.
            """
            if len(self.s2) == 0:
                while self.s1:
                    self.s2.append(self.s1.pop())
            return self.s2.pop()
            
        def peek(self) -> int:
            """
            Get the front element.
            """
            if len(self.s2) != 0:
                return self.s2[-1]
            return self.front
    
        def empty(self) -> bool:
            """
            Returns whether the queue is empty.
            """
            return (len(self.s1) is 0 and len(self.s2) is 0)

    题目234题

    回文链表

    请判断一个链表是否为回文链表。

    思路

    递归

    实现

    class Solution:
        def isPalindrome(self, head: ListNode) -> bool:
            self.pre = head
            def prev(node: ListNode):
                if node:
                    if not prev(node.next):
                        return False
                    if self.pre.val != node.val:
                        return False
                    self.pre = self.pre.next
                return True
            return prev(head)

    题目235题

    二叉搜索树的最近公共祖先

    给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

    百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。

    思路

    利用二叉搜索树的特性

    我们从根节点开始遍历;

    如果当前节点的值大于 p和 q 的值,说明 p 和 q 应该在当前节点的左子树,因此将当前节点移动到它的左子节点;

    如果当前节点的值小于 p和 q的值,说明 p 和 q 应该在当前节点的右子树,因此将当前节点移动到它的右子节点;

    如果当前节点的值不满足上述两条要求,那么说明当前节点就是「分岔点」。此时,pp 和 qq 要么在当前节点的不同的子树中,要么其中一个就是当前节点。

    实现

    class Solution:
        def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
            node = root
            while node:
                if node.val < q.val and node.val < p.val:
                    node = node.right
                elif node.val > q.val and node.val > p.val:
                    node = node.left
                else:
                    return node

    题目236题

    二叉树的最近公共祖先

    给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

    百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

    思路实现

    class Solution:
        def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
            result = []
            def dfs(node, ans, target):
                if node:
                    if node is target:
                        result.append(ans + [node])
                    dfs(node.left, ans + [node], target)
                    dfs(node.right, ans + [node], target)
            dfs(root, [],q)
            dfs(root, [],p)
            m = result[0]
            n = result[1]
            for i in range( min(len(m), len(n)) ):
                if m[i] != n[i]:
                    break
                res = m[i]
            return res

     

  • 相关阅读:
    选项卡
    使用script创建标签添加属性值和添加样式
    判断表单不能为空(表格形式的)
    数组
    关于meta元信息元素
    js判断数据类型
    Ising模型的Metropolis模拟中的组态阻塞和振荡
    python 画能级图
    python 调用 shell 命令,制作用户界面
    打包 python 程序,变成一个可执行文件
  • 原文地址:https://www.cnblogs.com/mgdzy/p/13813475.html
Copyright © 2011-2022 走看看