1.算法 - 双指针
- 普通双指针:两个指针往同一个方向移动
- 对撞双指针:两个指针面对面移动(有序数列)
- 快慢双指针:慢指针+快指针(环形链表)
141.环形链表
class Solution:
# Time Complexity: O(N)
# Space Complexity: O(1)
def hasCycle(self, head: ListNode) -> bool:
if head is None:
return False
slow = head
fast = head
while fast is not None and fast.next is not None:
fast = fast.next.next
slow = slow.next
if slow == fast:
return True
retrun False
881.救生艇
class Solution:
# Time Complexity: O(NlogN)
# Space Complexity: O(1)
def numRescueBoats(self, people: List[int], limit: int) -> int:
if people is None or len(people) == 0:
retrun 0
people.sort()
i = 0
j = len(people) - 1
res = 0
while (i <= j):
if people[i]+people[j] <= limit:
i = i + 1
j = j - 1
res = res + 1
return res
2.算法 - 二分查找法
有序数列
O(logN)
m = l + (r-l)//2
避免超过int型范围
- 二分查找
常规法:
class Solution(object):
# Time Complexity: O(N)
# Space Complexity: O(1)
def search(self, nums, target):
for i in range(len(nums)):
if nums[i] == target:
return i
return -1
二分查找法:
class Solution(object):
# Time Complexity: O(logN)
# Space Complexity: O(1)
def search(self, nums, target):
if nums == None or len(nums) == 0:
return -1
left, right = 0, len(nums)-1
while (left<=right):
mid = left + (right - left)//2
if nums[mid] == target:
return mid
elif nums[mid] > target:
right = mid - 1
else:
left = mid + 1
return -1
- 搜索插入位置
常规法:
class Solution(object):
# Time Complexity: O(N)
# Space Complexity: O(1)
def searchInsert(self, nums, target):
if nums == None or len(nums) == 0:
return 0
prev = -1
for i in range(len(nums)):
if nums[i] == target:
return i
elif num[i] < target:
prev = i
else:
return prev+1
return prev+1
二分查找法:
class Solution(object):
# Time Complexity: O(logN)
# Space Complexity: O(1)
def searchInsert(self, nums, target):
if nums == None or len(nums) == 0:
return 0
left, right = 0, len(nums)
while (left<right):
mid = left + (right - left)/2
if nums[mid] == target:
return mid
elif nums[mid] > target:
right = mid
else:
left = mid + 1
return left
- 寻找峰值
class Solution(object):
# Time Complexity: O(logN)
# Space Complexity: O(1)
def findPeakElement(self, nums: List[int]) -> int:
if nums is None or len(nums) == 0:
return -1
l = 0
r = len(nums) - 1
while l < r:
mid = l + (r-l)//2
if nums[mid] > nums[mid+1]:
r = mid
else:
l = mid + 1
return l
- 搜索二维矩阵
class Solution(object):
# Time Complexity: O(logN)
# Space Complexity: O(1)
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
if matrix is None or len(matrix) == 0:
return False
row = len(matrix)
col = len(matrix[0])
l = 0
r = row * col - 1
while l <= r:
m = l + (r-l)//2
element = matrix[m//col][m%col]
if element == target:
return True
elif element > target:
r = m - 1
else:
l = m + 1
return False
3.算法 - 滑动窗口法
目的:减少while循环
数组中的定长问题
- 长度最小的子数组
暴力法:
class Solution(object):
# Time Complexity: O(N^2)
# Space Complexity: O(1)
def minSubArrayLen(self, s: int, nums: List[int]) -> int:
if nums is None or len(nums) == 0:
return 0
size = 1
while size <= len(nums):
for i in range(len(nums)-size+1):
total = sum(nums[i: i+size])
if total >= s:
return size
size += 1
return 0
滑动窗口法(双指针法):
class Solution(object):
# Time Complexity: O(N)
# Space Complexity: O(1)
def minSubArrayLen(self, s: int, nums: List[int]) -> int:
if nums is None or len(nums) == 0:
return 0
result = len(nums) + 1
total = 0
i, j = 0, 0
while j < len(nums):
total += num[j]
j += 1
while total >= s:
result = min(result, j - i)
total -= nums[i]
i += 1
return 0 if result == len(nums)+1 else result
- 定长子串中元音的最大数目
class Solution(object):
# Time Complexity: O(N)
# Space Complexity: O(1)
def maxVowels(self, s: str, k: int) -> int:
if s is None or len(s) == 0 or len(s) < k:
return 0
hashset = set(['a', 'o', 'e', 'i', 'u'])
res = 0
count = 0
for i in range(0, k):
if s[i] in hashset:
count = count + 1
res = max(res, count)
for i in range(k, len(s)):
out = s[i-k]
inc = s[i]
if out in hashset:
count = count - 1
if inc in hashset:
count = count + 1
res = max(res, count)
return res
4.算法 - 递归法
函数直接或间接调用自己
- 递归
- 回溯
- 深度优先搜索
- 分治法
4个要素
- 接受的参数
- 返回值
- 终止的条件
- 递归拆解:如何递归下一层
- 斐波那契数
class Solution(object):
# Time Complexity: O(N)
# Space Complexity: O(N)
def fib(self, N: int) -> int:
if N < 2:
return 0 if N == 0 else 1
m = self.fib(N-1) + self.fib(N-2)
return m
- 反转链表
迭代法:
class Solution(object):
# Time Complexity: O(N)
# Space Complexity: O(1)
def reverseList(self, head: ListNode) -> ListNode:
dummy = ListNode()
dummy.next = head
while (head != None and head.next != None):
dummy_next = dummy.next
temp = head.next
dummy.next, head.next, temp.next = temp, temp.next, dummy_next
return dummy.next
递归法:
class Solution(object):
# Time Complexity: O(N)
# Space Complexity: O(N)
def reverseList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
p = self.reverseList(head.next)
head.next.next = head
head.next = None
return p
- 反转字符串
class Solution(object):
# Time Complexity: O(N/2)
# Space Complexity: O(N/2)
def reverseString(self, s: List[str]) -> None:
self.recursion(s, 0, len(s)-1)
def recursion(self, s, left, right):
if left >= right:
return
self.recursion(s, left+1, right-1)
s[left], s[right] = s[right], s[left]
5.算法 - 分治法
大问题切割成一个个小问题
用到递归,自己调用自己
- 多数元素
class Solution(object):
# Time Complexity: O(NlogN)
# Space Complexity: O(logN)
def majorityElement(self, nums: List[int] -> int:
return self.getMajority(nums, 0, len(nums)-1)
def getMajority(self, nums, left, right):
if left == right:
return nums[left]
mid = left + (right - left) // 2
leftMajority = self.getMajority(nums, left, mid)
rightMajority = self.getMajority(nums, mid+1, right)
if leftMajority == rightMajority:
return leftMajority
leftCount = 0
rightCount = 0
for i in range(left, right+1):
if nums[i] == leftMajority:
leftCount += 1
elif nums[i] == rightMajority:
right += 1
return leftMajority if leftCount > rightCount else rightMajority
- 最大序列和
class Solution(object):
# Time Complexity: O(N)
# Space Complexity: O(logN)
def maxSubArray(self, nums: List[int]) -> int:
return self.getMax(nums, 0, len(nums)-1)
def getMax(self, nums, l, r):
if l == r:
return nums[l]
mid = l + (r-l)//2
leftSum = self.getMax(nums, l, mid)
rightSum = self.getMax(nums, mid+1, r)
crossSum = self.crossSum(nums, l, r)
return max(leftSum, rightSum, crossSum)
def crossSum(self, nums, l, r):
mid l + (r-l)//2
# from mid to leftmost
leftSum = nums[mid]
leftMax = leftSum
for i in range(mid-1, l-1, -1):
leftSum += nums[i]
leftMax = max(leftMax, leftSum)
# from mid to rightmost
rightSum = nums[mid+1]
rightMax = rightSum
for i in range(mid+2, r+1):
rightSum += nums[i]
rightMax = max(rightMax, rightSum)
return leftMax + rightMax
6.算法 - 回溯法
类似枚举,一层一层向下递归,尝试搜索答案
找到答案
尝试别的可能
返回答案
找不到答案
返回上一层递归,尝试别的路径
- 括号生成
class Solution(object):
def generateParenthesis(self, n: int) -> List[str]:
result = []
self.backtracking(n, result, 0, 0, "")
return result
def backtracking(self, n, result, left, right, s):
if right > left:
return
if (left == n and right == n):
result.append(s)
return
if left < n:
self.backtracking(n, result, left+1, right, s+"(")
if right < n:
self.backtracking(n, result, left, right+1, s+")")
- 子集
暴力法:
class Solution(object):
# Time Complexity: O(N*2^N)
# Space Complexity: O(N*2^N)
def subsets(self, nums: List[int]) -> List[List[int]]:
result = [[]]
for num in nums:
# result = result + [cur+[num] for cur in result]
temp = []
for cur in result:
temp.append(cur+[num])
for t in temp:
result.append(t)
return result
回溯法:
class Solution(object):
# Time Complexity: O(N*2^N)
# Space Complexity: O(N*2^N)
def subsets(self, nums: List[int]) -> List[list[int]]:
result = [[]]
for i in range(1, len(nums)+1):
self.backtracking(nums, result, i, 0, [])
return result
def backtracking(self, nums, result, length, index, subset):
if len(subset) == lenth:
result.append(subset[:])
return
for i in range(index, len(nums)):
subset.append(nums[i])
self.backtracking(nums, result, length, i+1, subset)
subset.pop()
7.算法 - 深度优先搜索算法DFS
从root节点开始,尽可能深的搜索每一个分支(把一个分支的结果搜索完,再去看下一个分支)
- 二叉树搜索
- 图搜索
回溯算法 = DFS + 剪枝
- 子集
class Solution(object):
# Time Complexity: O(N*2^N)
# Space Complexity: O(N*2^N)
def subsets(self, nums: List[int]) -> List[List[]]:
result = []
self.dfs(nums, result, 0, [])
return result
def dfs(self, nums, result, index, subset):
result.append(subset[:])
if index == len(nums);
return
for i in range(index, len(nums)):
subset.append(nums[i])
self.dfs(nums, result, i+1, subset)
subset.pop()
- 岛屿数量
# R is the row of grid
# C is the column of grid
class Solution(object):
# Time Complexity: O(RC)
# Space Complexity: O(RC)
def numIslands(self, grid: List[List[str]]) -> int:
if grid is None or len(grid) == 0:
return 0
result = 0
row = len(grid)
col = len(grid[0])
for i in range(0, row):
for j in range(0, col):
if grid[i][j] == '1':
result = result + 1
self.dfs(grid, i, j, row, col)
return result
def dfs(self, grid, x, y, row, col):
if x < 0 or y < 0 or x >= row or y >= col or grid[i][j] == '0':
return
grid[x][y] = '0'
self.dfs(grid, x-1, y, row, col)
self.dfs(grid, x+1, y, row, col)
self.dfs(grid, x, y-1, row, col)
self.dfs(grid, x, y+1, row, col)
8.算法 - 广度优先搜索算法BFS
层层递进,一层一层遍历
- 二叉树搜索
- 图搜索
- 二叉搜索树的范围和
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
# Time Complexity: O(N)
# Space Complexity: O(N)
def rangeSumBST(self, root: TreeNode, low: int, high: int) -> int:
result = 0
queue = []
queue.append(root)
while len(queue) > 0:
size = len(queue)
while size > 0:
cur = queue.pop()
if cur.val >= low and cur.val <= high:
result = result + cur.val
if cur.left is not None:
queue.append(cur.left)
if cur.right is not None:
queue.append(cur.right)
size = size - 1
return result
- 二叉树的层序遍历
from collections import deque
class Solution(object):
# Time Complexity: O(N)
# Space Complexity: O(N)
def levelOrder(self, root: TreeNode) -> List[List[]]:
result = []
if roor is None:
return result
q = deque([])
q.append(root)
while len(q) > 0:
size = len(q)
ls = []
while size > 0:
cur = q.popleft
ls.append(cur.val)
if cur.left is not None:
q.append(cur.left)
if cur.right is not None:
q.append(cur.right)
size = size - 1
result.append(ls[:])
return result
- 二叉树的层序遍历2
class Solution(object):
# Time Complexity: O(N)
# Space Complexity: O(N)
def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
result = []
if root is None:
return result
q = deque([])
q.append(root)
temp = deque([])
while len(q) > 0:
size = len(q)
ls = []
while size > 0:
cur = q.popleft()
ls.append(cur.val)
if cur.left is not None:
q.append(cur.left)
if cur.right is not None:
q.append(cur.right)
size = size - 1
temp.appendleft(ls[:])
result = list(temp)
retutn result
- 岛屿数量
# R is the row of grid
# C is the column of grid
class Solution(object):
# Time Complexity: O(RC)
# Space Complexity: O(RC)
def numIslands(self, grid: List[List[str]] -> int:
if grid is None or len(grid) == 0:
return 0
result = 0
row = len(grid)
col len(grid[0])
queue = []
for i in range(0, row):
for j in range(0, col):
if grid[i][j] == '1':
result = result + 1
queue.append([i,j])
grid[i][j] = '0'
while len(queue) > 0:
cur = queue.pop()
x = cur[0]
y = cur[1]
if x-1 >= 0 and grid[x-1][y] == '1':
queue.append([x-1, y])
grid[x-1][y] = '0'
if y-1 >= 0 and grid[x][y-1] == '1':
queue.append([x][y-1])
grid[x][y-1] = '0'
if x+1 < row and grid[x+1][y] == '1':
queue.append([x+1][y])
grid[x+1][y] = '0'
if y+1 < col and grid[x][y+1] == '1':
queue.append([x][y+1])
grid[x][y+1] = '0'
return result
9.算法 - 并查集算法
Union:
合并两个元素为同一个根节点
Find:
找到某个元素的根节点
Union(x, y)
root Find(x)
- 岛屿数量
class Solution(object):
# Time Complexity: O(RC)
# Space Complexity: O(RC)
def numIslands(self, grid: List[List[str]]) -> int:
if grid is None or len(grid) == 0:
return 0
row = len(grid)
col = lenj(grid[0])
waters = 0
uf = UnionFind(grid)
for i in range(0, row):
for j in range(0, col):
if grid[i][j] == '0'
waters += 1
else:
directions = [(0,1), (0,-1), (-1,0), (1,0)]
for x, y in directions:
x = x + i
y = y + j
if x>=0 and y>=0 and x<row and y<col and grid[x][y] == '1':
uf.union(x*col+y, i*col+j)
return uf.getCount() - waters
class UnionFind:
def __init__(self, grid):
row = len(grid)
col = len(grid[0])
self.root = [-1]*(row*col)
self.count = row*col
for i in range(0, row*col):
self.root[i] = i
def find(self, x):
if x == self.root[x]:
return self.root[x]
else:
self.root[x] = self.find(self.root[x])
return self.root[x]
def union(self, x, y):
rootX = self.find(x)
rootY = self.find(y)
if rootX != rootY:
self.root[rootX] = rootY
self.count -= 1
def getCount(self):
return self.count
- 朋友圈
并查集优化
Quick Find
self.root[x] = self.find(self.root[x])
return self.root[x]
Quick Union - 权重
防止树太高
比较两个树的高
把矮的树连接到高的树上
使树的高度最低
if rootx != rooty:
if self.rank[rootx] > self.rank[rooty]:
root[rooty] = rootx
elif self.rank[rootx] < self.rank[rooty]:
root[rootx] = rooty
else:
root[rooty] = rootx
self.rank[rootx] += 1
10.算法 - 贪心算法
每一步做出的都是当前看起来最好的选择
只是局部最优解
而不是整体的最优选择
-
零钱兑换
-
玩筹码
55.跳跃游戏
11.算法 - 记忆化搜索
减少重复计算
-
斐波那契数
-
零钱兑换
12.算法 - 动态规划
动态规划三要素
- 初始状态
- 方程式
- 终止状态
-
计数:有多少种方法
机器人从左上角到右下角有多少种路径 -
求最值:
机器人从左到右路径的最大数字和 -
求存在性:是否存在某个可能
是否存在机器人从左到右的路径 -
斐波那契数
-
不同路径
-
买卖股票的最佳时机
-
爬楼梯
-
完全平方数
-
最大正方形
学习视频来源B站—爱学习的饲养员—手把手带你刷Leetcode力扣