题目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(i−1,j),dp(i−1,j−1),dp(i,j−1))+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.
3.
题目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