一、双指针
二、排序
三、贪心算法
四、二分查找
五、分治算法
六、搜索(DFS&BFS)
七、动态规划
八、递归
九、回溯
十、查并集
十一、滑动窗口
十二、记忆化搜索
一、双指针
题号:86、167、209
【典型题目】给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target
class Solution: def twoSum(self, numbers: List[int], target: int) -> List[int]: i = 0 j = len(numbers) - 1 while i < j: if target - numbers[j] == numbers[i]: return [i + 1, j + 1] elif numbers[i] + numbers[j] > target: j -= 1 else: i += 1 return []
二、排序
题号:207、210
1. 转换成堆,堆 :时间复杂度 O(NlogK),空间复杂度 O(K)。
【典型题目】在某个集合中找出最大或最小的N个元素
import heapq >>> nums=[1,8,2,23,7,-4,18,23,42,37,2] >>> print(heapq.nlargest(3,nums)) [42, 37, 23] >>> print(heapq.nsmallest(3,nums)) [-4, 1, 2]
【典型题目】如果正在寻找最大或者最小的N个元素,且同集合中元素的总数目相比,N很小,那么下面这些函数就可以提供更好的性能。
这些函数首先会在底层将数据转化成列表,且元素会以堆得顺序排列。例如:
>>> nums=[1,8,2,23,7,-4,18,23,42,37,2] >>> import heapq >>> heap=list(nums) >>> heapq.heapify(heap)#将列表原地转换成堆 >>> heap [-4, 2, 1, 23, 7, 2, 18, 23, 42, 37, 8]
2. 排序 :时间复杂度 O(NlogN),空间复杂度 O(1)
3. 快速选择 :时间复杂度 O(N),空间复杂度 O(1)
4. 拓扑排序:是专门应用于有向图的算法,BFS 的写法就叫「拓扑排序」,这里还用到了贪心算法的思想,贪的点是:当前让入度为 0 的那些结点入队
三、贪心算法
题号:322、1217、55
四、二分查找
题号:704、35、162、74
【典型题目】给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1
class Solution: def search(self, nums: List[int], target: int) -> int: left, right = 0, len(nums)-1 while left <= right: mid = left + (right - left) // 2 if nums[mid] > target: right = mid - 1 elif nums[mid] < target: left = mid + 1 elif nums[mid] == target: return mid return -1
【典型题目】编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值
class Solution: def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: n , m = len(matrix) , len(matrix[0]) if m == 0 or n == 0 :return False l , r = 0 , m * n - 1 while (l <= r): mid = (l + r) // 2 if(matrix[mid // m][mid % m] > target): r = mid - 1 elif(matrix[mid // m][mid % m] < target): l = mid + 1 else: return True return False
五、分治算法
题号:169、53
【典型题目】给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
注:便捷算法
class Solution: def maxSubArray(self, nums: List[int]) -> int: res = nums[0] sum = 0 for num in nums: if sum > 0 : sum += num else: sum = num res = max(res,sum) return res
六、搜索(DFS&BFS)
1. DFS 题号:938、78、200
【典型题目】给定二叉搜索树的根结点 root,返回值位于范围 [low, high] 之间的所有结点的值的和。
class Solution: def rangeSumBST(self, root: TreeNode, low: int, high: int) -> int: if root==None: return 0 ans_left = self.rangeSumBST(root.left, low, high) ans_right = self.rangeSumBST(root.right, low, high) rootval = root.val if low<=root.val<=high else 0 return ans_left + ans_right + rootval
【典型题目】给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
方法一==>DFS:
class Solution: def dfs(self, res, nums, cur, index): if index >= len(nums): res.append(cur.copy()) # 注意这里要用copy 要不然cur的改变会影响到res里的cur return # 下面有两个dfs 表示每个状态有两个子状态可供选择 # 每个index前后保证状态不变 cur.append(nums[index]) self.dfs(res, nums, cur, index + 1) cur.pop() self.dfs(res, nums, cur, index + 1) def subsets(self, nums: List[int]) -> List[List[int]]: # 本题定义状态为(cur, index) res = [] self.dfs(res, nums, [], 0) return res
方法二==>递归:
class Solution(object): def subsets(self, nums): if nums ==[]: return [[]] return self.subsets(nums[:-1]) + [i+[nums[-1]] for i in self.subsets(nums[:-1])]
【典型题目】岛屿数量
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
方法一==>DFS
class Solution: def numIslands(self, grid: List[List[str]]) -> int: if not grid: return 0 count = 0 for i in range(len(grid)): for j in range(len(grid[0])): if grid[i][j] == '1': self.dfs(grid, i, j) count += 1 return count def dfs(self, grid, i, j): if i < 0 or j < 0 or i >= len(grid) or j >= len(grid[0]) or grid[i][j] != '1': return grid[i][j] = '0' self.dfs(grid, i + 1, j) self.dfs(grid, i - 1, j) self.dfs(grid, i, j + 1) self.dfs(grid, i, j - 1)
方法二==>BFS
class Solution: def numIslands(self, grid: List[List[str]]) -> int: count = 0 for row in range(len(grid)): for col in range(len(grid[0])): if grid[row][col] == '1': # 发现陆地 count += 1 # 结果加1 grid[row][col] = '0' # 将其转为 ‘0’ 代表已经访问过 # 对发现的陆地进行扩张即执行 BFS,将与其相邻的陆地都标记为已访问 # 下面还是经典的 BFS 模板 land_positions = collections.deque() land_positions.append([row, col]) while len(land_positions) > 0: x, y = land_positions.popleft() for new_x, new_y in [[x, y + 1], [x, y - 1], [x + 1, y], [x - 1, y]]: # 进行四个方向的扩张 # 判断有效性 if 0 <= new_x < len(grid) and 0 <= new_y < len(grid[0]) and grid[new_x][new_y] == '1': grid[new_x][new_y] = '0' # 因为可由 BFS 访问到,代表同属一块岛,将其置 ‘0’ 代表已访问过 land_positions.append([new_x, new_y]) return count
2. BFS 题号:102、107、200
【典型题目】102题:给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
当遍历到新的一层的时候(也就是depth>=res数组的长度的时候),就往res里append一个空列表用于存储新的一层的结点值
同时往该结点对应那一层的列表里(res[depth])append结点的值对该结点的左子节点和右子节点重复以上工作,由于是从上到下存储的各层元素,所以最后需要倒转一下列表。
DFS
class Solution: def levelOrderBottom(self, root: TreeNode) -> List[List[int]]: res = [] def dfs(root, depth): if not root: return if len(res)<depth+1: res.append([]) res[depth].append(root.val) dfs(root.left, depth+1) dfs(root.right, depth+1) dfs(root,0) return res[::-1]
七、动态规划
题号:62、322、1143、509、121、70、279、22
【典型题目】给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。你可以认为每种硬币的数量是无限的。
class Solution: def coinChange(self, coins: List[int], amount: int) -> int: dp = [float('inf')] * (amount + 1) dp[0] = 0 for coin in coins: for i in range(coin, amount + 1): dp[i] = min(dp[i], 1 + dp[i - coin]) return dp[amount] if dp[amount] != float('inf') else -1
【典型题目】给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。
若这两个字符串没有公共子序列,则返回 0。
class Solution(object): def longestCommonSubsequence(self, text1, text2): """ :type text1: str :type text2: str :rtype: int """ if not text1 or not text2: return 0 #base case n = len(text1) m = len(text2) dp = [[0 for x in range(n+1)] for y in range(m+1)] for i in range(1,m+1): for j in range(1,n+1): if text1[j-1] == text2[i-1]: dp[i][j] = dp[i-1][j-1] + 1 else: dp[i][j] = max(dp[i-1][j], dp[i][j-1]) return dp[m][n]
八、递归
题号:509、206、344、687
【典型题目】斐波那契数列
方法一==>纯递归
class Solution: def fib(self, n: int) -> int: if n == 0 or n == 1 : return n else: return self.fib(n - 1) + self.fib( n - 2)
方法二==>递归+记忆法(数组)
class Solution: def fib(self, n: int) -> int: memo=[0,1] i=2 if n<2: return memo[n] while i<=n: memo.append(memo[i-1]+memo[i-2]) i+=1 return memo[-1]
方法三==>动态规划
class Solution: def fib(self, n: int) -> int: if n == 0: return 0 if n <= 2: return 1 first = 1 second = 1 for i in range(3, n+1): first, second = second, first + second return second
【典型题目】反转一个链表
class Solution: def reverseList(self, head: ListNode) -> ListNode: if not head or head.next == None: return head res = self.reverseList(head.next) head.next.next = head head.next = None return res
【典型题目】反转字符串
双指针法
class Solution: def reverseString(self, s: List[str]) -> None: """ Do not return anything, modify s in-place instead. """ # double pointer i,j = 0,len(s)-1 while i<j: s[i],s[j] = s[j],s[i] i+=1;j-=1
九、回溯
题号:22、78、77、46
【典型题目】给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
class Solution: def combine(self, n: int, k: int) -> List[List[int]]: res = [] def backtrack(i, k, tmp): if k == 0: res.append(tmp) return for j in range(i, n + 1): backtrack(j+1, k-1, tmp + [j]) backtrack(1, k, []) return res
十、并查集
题号:200、547、721
十一、滑动窗口
题号:209、1456
十二、记忆化搜索
题号:509、322