1. 快速排序
# Python最简版from random import randint
def quick_sort(arr): if len(arr) <= 1: return arr p = arr[randint(0, len(arr) - 1)] left = [x for x in arr if x < p] mid = [x for x in arr if x == p] right = [x for x in arr if x > p]
return quick_sort(left) + mid + quick_sort(right)
a = [randint(0, 100000) for x in range(100000)]print(quick_sort(a))
2. 堆排序
class Solution(object): def __init__(self, nums): self.nums = nums
def heap_sort(self): i, length = 0, len(self.nums) # 构造大顶堆,从非叶子节点开始倒序遍历,因此是length // 2 - 1 就是最后一个非叶子节点 for i in range(length // 2 - 1, -1, -1): self.build_heap(i, length - 1) # 上面的循环完成了大顶堆的构造,那么就开始把根节点跟末尾节点交换,然后重新调整大顶堆 for j in range(length - 1, -1, -1): self.nums[0], self.nums[j] = self.nums[j], self.nums[0] # 交换 self.build_heap(0, j - 1) # 从堆顶开始调整 return self.nums
def build_heap(self, i, length): """构建大顶堆""" left, right = 2 * i + 1, 2 * i + 2 # 左右子节点的下标 large_index = i if left <= length and self.nums[i] < self.nums[left]: large_index = left if right <= length and self.nums[large_index] < self.nums[right]: large_index = right if large_index != i: self.nums[large_index], self.nums[i] = self.nums[i], self.nums[large_index] self.build_heap(large_index, length)
solution = Solution([2, 3, 5, 4, 7, 6, 8])print(solution.heap_sort())# 小顶堆的话只需要把<改成>号即可
3. 寻找数组中出现一次的数,其他出现3次及以上
"""
出现三次或者三次以上去找那个单独的值的时候该怎么办呢?好像不能用异或了,但是考虑到输入是int型数组,所以可以用32位来表达输入数组的元素。
假设输入中没有single number,那么输入中的每个数字都重复出现了数字,也就是说,对这32位中的每一位i而言,所有的输入加起来之后,第i位一定是3的倍数。
现在增加了single number,那么对这32位中的每一位做相同的处理,也就是说,逐位把所有的输入加起来,并且看看第i位的和除以3的余数,这个余数就是single numer在第i位的取值。
这样就得到了single number在第i位的取值。这等价于一个模拟的二进制,接着只需要把这个模拟的二进制转化为十进制输出即可。
"""nums = [1, 2, 2, 2, 3, 3, 3]dp = [0] * 32for i in nums: for j in range(32): dp[j] = dp[j] + ((i >> j) & 1) # 首先把输入数字的第i位加起来,这里和1去与,取到的就是一位
res = 0for i in range(32): if dp[i] % 3 != 0: res = res | (1 << i)print(res)
4. 寻找数组中两个出现一次的数,其他数出现2次
# 假设这两个不同的数分别为a,b,根据异或运算最后得到a^b,因为a和b不同,所以a^b必定存在某个二进制位置k,a为0,b为1,或者相反。找到第一个不同的位置即可,将a和b分开。nums = [5, 2, 3, 3]res = 0for i in nums: res ^= i
k = 0while (res >> k) & 1 == 0: k = k + 1
res1 = 0res2 = 0for i in nums: if (i >> k) & 1: res1 ^= i else: res2 ^= iprint(res1, res2)
5. 划分瓶子
import numpy as np
dp = np.zeros(10)a = np.array([1, 2, 3, 5])b = sum(a)
for i in range(len(a)): for j in range(b // 2, a[i] - 1, -1): dp[j] = max(dp[j], dp[j - a[i]] + a[i])
if int(b - 2 * dp[b // 2]) == 0: print("1")else: print("0")
6. 两座岛相连起来的桥的最短长度
# 题目意思:"""
二维数组,0表示海洋,1表示岛屿,存在两座岛,问使得两座岛相连起来的桥的最短长度,如果两座岛相连,则输出0
"""def shortestBridge(A): row, col = len(A), len(A[0]) visited = [[0] * col for _ in range(row)] # 负责记录其中的一个岛 q = [] start = [] # 保存其中一个岛的所有位置 found = False for i in range(row): # 先找到一个岛中其中一个位置 for j in range(col): if A[i][j] == 1: found = True q.append((i, j)) visited[i][j] = 1 break if found: break
while q: # 以其中一个岛的位置为基础,使用广度优先搜索方法,继续找到这个岛的其他位置 tmp = [] for a in q: x, y = a[0], a[1] start.append(a) # 把岛的位置放到 start 队列里面 if (x - 1 >= 0) and (visited[x - 1][y] == 0) and (A[x - 1][y] == 1): tmp.append((x - 1, y)) visited[x - 1][y] = 1 if (x + 1 < col) and (visited[x + 1][y] == 0) and (A[x + 1][y] == 1): tmp.append((x + 1, y)) visited[x + 1][y] = 1 if (y - 1 >= 0) and (visited[x][y - 1] == 0) and (A[x][y - 1] == 1): tmp.append((x, y - 1)) visited[x][y - 1] = 1 if (y + 1 < row) and (visited[x][y + 1] == 0) and (A[x][y + 1] == 1): tmp.append((x, y + 1)) visited[x][y + 1] = 1 q = tmp
ans = 0 while start: # 从一个岛出发,去找探索另外一个岛 tmp = [] for a in start: # 广度优先算法,一层一层的探查 是否 到达另外一个岛 x, y = a[0], a[1] if (x - 1 >= 0) and (visited[x - 1][y] == 0): if A[x - 1][y] == 1: return ans else: tmp.append((x - 1, y)) visited[x - 1][y] = 1 if (x + 1 < col) and (visited[x + 1][y] == 0): if A[x + 1][y] == 1: return ans else: tmp.append((x + 1, y)) visited[x + 1][y] = 1 if (y - 1 >= 0) and (visited[x][y - 1] == 0): if A[x][y - 1] == 1: return ans else: tmp.append((x, y - 1)) visited[x][y - 1] = 1 if (y + 1 < row) and (visited[x][y + 1] == 0): if A[x][y + 1] == 1: return ans else: tmp.append((x, y + 1)) visited[x][y + 1] = 1
start = tmp # 探索了一层之后,没有发现另外一个岛,则更新最外层边界以及路径长度 ans += 1
return ans
if __name__ == '__main__': A = [[1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 1, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1]] print(shortestBridge(A))
7. 链表相交
# Definition for singly-linked list.# class ListNode(object):# def __init__(self, x):# self.val = x# self.next = None
class Solution(object): def getIntersectionNode(self, headA, headB): """
:type head1, head1: ListNode
:rtype: ListNode
""" cur1 = headA cur2 = headB # 链表不相交的情况,两个NULL指针相等跳出循环 while cur1 != cur2: cur1 = cur1.next if cur1 else headB cur2 = cur2.next if cur2 else headA return cur1
8. 求数组中第K个最大的元素
import random
def partition(arr, low, high): """
将小于中轴元素的一次排在前面,从0开始
:param arr:
:param low:
:param high:
:return:
""" x = arr[high] i = low - 1 for j in range(low, high): if arr[j] <= x: i += 1 arr[i], arr[j] = arr[j], arr[i] arr[i + 1], arr[high] = arr[high], arr[i + 1] # 将中轴元素调回,使得中轴元素左边小于中轴,右边大于中轴 return i + 1
def randomPartition(arr, low, high): """
将中轴元素放置在最后面
:param arr:
:param low:
:param high:
:return:
""" rand_num = random.randint(low, high) arr[rand_num], arr[high] = arr[high], arr[rand_num] return partition(arr, low, high)
def quick_sort(arr, low, high, k=None): # par_num = randomPartition(arr, low, high) # if par_num == k: # return arr[k] # elif par_num > k: # return quick_sort(arr, low, par_num - 1, k) # else: # return quick_sort(arr, par_num + 1, high, k) if low < high: par_num = randomPartition(arr, low, high) quick_sort(arr, low, par_num - 1) quick_sort(arr, par_num + 1, high)
arr = [2, 5, 5, 3]n = len(arr)k = 3quick_sort(arr, 0, n - 1)print(arr)
9. 旋转数组搜索问题
# 适用于重复和非重复的找目标值的两种情况class Solution(object): def search(self, nums, target): """
:type nums: List[int]
:type target: int
:rtype: int
""" left = 0 right = len(nums) - 1 while left <= right: mid = (left + right) >> 1 if nums[mid] == target: return mid if nums[mid] > nums[right]: # mid左边单调递增 if nums[left] <= target < nums[mid]: right = mid -1 else: left = mid + 1
elif nums[mid] < nums[right]: if nums[mid] < target <= nums[right]: left = mid + 1 else: right = mid - 1 else: right = right - 1
return -1
# 旋转多次数组求目标值的最小索引 class Solution(object): def search(self, nums, target): """
:type nums: List[int]
:type target: int
:rtype: int
""" left = 0 right = len(nums) - 1 while left < right: mid = (left + right) >> 1 if nums[mid] > nums[left]: # 左区间单调递增 if nums[left] <= target <= nums[mid]: right = mid else: left = mid + 1
elif nums[mid] < nums[left]: # 右区间单调递增 if target <= nums[mid] or target >= nums[left]: right = mid else: left = mid + 1 else: if nums[left] != target: left += 1 else: right = left return left if nums[left] == target else -1
# 旋转多次数组求目标值的最大索引class Solution(object): def search(self, nums, target): """
:type nums: List[int]
:type target: int
:rtype: int
""" left = 0 right = len(nums) - 1 while left < right: mid = (left + right) // 2 if nums[mid] < nums[right]: # 右区间单调递增 if nums[mid] <= target <= nums[right]: if mid == left: if nums[mid] == target: return mid
if nums[right] == target: return right else: left = mid else: right = mid - 1
elif nums[mid] > nums[right]: # 左区间单调递增 if target <= nums[right] or target >= nums[mid]: left = mid else: right = mid - 1
else: if nums[mid] != target: right -= 1 else: break return right if nums[right] == target else -1
print(Solution().search([15, 16, 19, 20, 25, 1, 3, 4, 5, 5, 7, 10, 14], 5))
# 找最小值class Solution(object): def minArray(self, numbers): """
:type numbers: List[int]
:rtype: int
""" left = 0 right = len(numbers) - 1 while left < right: mid = (left + right) >> 1 if numbers[mid] > numbers[right]: # 最小值在[mid+1,right]中间 left = mid + 1 elif numbers[mid] < numbers[right]: # 最小值在[left,mid]中间 right = mid elif numbers[mid] == numbers[right]: # 无法判断在左边还是右边,那最小值可以用mid代替,right舍弃即可 right -= 1 return numbers[left]
# 找最大值class Solution(object): def minArray(self, numbers): """
:type numbers: List[int]
:rtype: int
""" left = 0 right = len(numbers) - 1 while left < right: mid = (left + right) >> 1 if numbers[mid] > numbers[right]: # 最小值在[mid,right]中间 left = mid elif numbers[mid] < numbers[right]: # 最小值在[left,mid]中间 right = mid - 1 elif numbers[mid] == numbers[right]: # 无法判断在左边还是右边 right -= 1 return numbers[left]
10. 最大岛屿数目
class Solution: def dfs(self, grid, r, c): grid[r][c] = 0 nr, nc = len(grid), len(grid[0]) for x, y in [(r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)]: if 0 <= x < nr and 0 <= y < nc and grid[x][y] == "1": self.dfs(grid, x, y)
def numIslands(self, grid: List[List[str]]) -> int: nr = len(grid) if nr == 0: return 0 nc = len(grid[0])
num_islands = 0 for r in range(nr): for c in range(nc): if grid[r][c] == "1": num_islands += 1 self.dfs(grid, r, c) return num_islands
11. 二叉树序列化和反序列化
class Codec:
def serialize(self, root): """Encodes a tree to a single string.
:type root: TreeNode
:rtype: str
""" if not root: return '[]' queue = collections.deque() queue.append(root) res = [] while queue: node = queue.popleft() res.append(str(node.val) if node else '#') if node: queue.extend([node.left, node.right]) # print(res) return '[' + ','.join(res) + ']' def deserialize(self, data): """Decodes your encoded data to tree.
:type data: str
:rtype: TreeNode
""" nodes = [TreeNode(int(v)) if v != '#' else None for v in data[1:-1].split(',')] # print(nodes) i,j = 0,1 while i < len(nodes): if nodes[i] is not None: nodes[i].left = nodes[j] j += 1 nodes[i].right = nodes[j] j += 1 i += 1 return nodes[0]
12. 最长不重复子串
class Solution: def lengthOfLongestSubstring(self, s: str) -> int: # 哈希集合,记录每个字符是否出现过 occ = set() n = len(s) # 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动 rk, ans = -1, 0 for i in range(n): if i != 0: # 左指针向右移动一格,移除一个字符 occ.remove(s[i - 1]) while rk + 1 < n and s[rk + 1] not in occ: # 不断地移动右指针 occ.add(s[rk + 1]) rk += 1 # 第 i 到 rk 个字符是一个极长的无重复字符子串 ans = max(ans, rk - i + 1) return ans
13. 硬币问题(最少硬币个数)
class Solution(object): def coinChange(self, coins, amount): """
:type coins: List[int]
:type amount: int
:rtype: int
""" dp = [1e9] * (amount + 1) dp[0] = 0 for i in coins: for j in range(i, amount + 1): dp[j] = min(dp[j], dp[j-i] + 1) return dp[amount] if dp[amount] != 1e9 else -1
14. 硬币问题(组合方式总数)
n = 7mod = 10**7 + 7nums = [1, 2, 3, 4, 5, 6]dp = [0] * (n + 1)dp[0] = 1for i in nums: for j in range(n, i - 1, -1): # 只能取一个;如果是能取多个的话,调换循环顺序 dp[j] = (dp[j] + dp[j - i]) % modprint(dp[n])
15. 背包问题
# 01 背包N, V = map(int, input().split())
v = [0] * Nw = [0] * N
for i in range(N): v[i], w[i] = map(int, input().split())
dp = [0] * (V + 1) # 初始化全0
for i in range(N): for j in range(V, v[i] - 1, -1): dp[j] = max(dp[j], dp[j - v[i]] + w[i])
print(dp[V])# 完全背包"""
换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第 i 件物品”这件策略时,依据的是一个绝无已经选入第 i 件物品的子结果 F[i − 1, v − Ci]。
而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第 i 种物品”这种策略时,却正需要一个可能已选入第 i 种物品的子结果 F[i, v − Ci],
所以就可以并且必须采用 v递增的顺序循环。
"""N, V = map(int, input().split())
v = [0] * Nw = [0] * N
for i in range(N): v[i], w[i] = map(int, input().split())
dp = [0] * (V + 1) # 初始化全0
for i in range(N): for j in range(v[i], V + 1): dp[j] = max(dp[j], dp[j - v[i]] + w[i])
print(dp[V])# 多重背包N, V = map(int, input().split())v = [0] * N # 体积w = [0] * N # 价值s = [0] * N # 个数dp = [0] * (V + 1)for i in range(N): v[i], w[i], s[i] = map(int, input().split())for i in range(N): for j in range(V, v[i] - 1, -1): for k in range(1, min(s[i], j // v[i]) + 1): dp[j] = max(dp[j], dp[j - k * v[i]] + k * w[i])
print(dp[V])
16. 链表反转
def reverse(head): pre = None cur = head while cur: t = cur.next cur.next = pre pre = cur cur = t return pre
17. 最小编辑距离
有两个字符串,str1,str2,可以通过以下操作将str1变成str2. 分别是字符串替换/删除/插入操作问最少需要多少种操作使得,str1变成str2?
# 动态规划思路设m,n分别为str1和str2的长度dp[m][n] 表示长度分别为m,n时的最小编辑距离,也就是最少操作次数if str1[m] == str2[n]: dp[m][n] = dp[m-1][n-1]else: if str1 删除 ----> 将str1[m]删除 dp[m][n] = dp[m-1][n] + 1 if str1 替换 ----> 将str1[m]替换成str2[n] dp[m][n] = dp[m-1][n-1] + 1 if str1 插入 ----> 在str1[m+1]处插入一个字符 dp[m][n] = dp[m][n-1] + 1
状态转移方程:dp[m][n] = min(dp[m-1][n] + 1, dp[m-1][n-1] + 1, dp[m][n-1] + 1)# 完整代码如下:class Solution(object): def minDistance(self, word1, word2): """
:type word1: str
:type word2: str
:rtype: int
""" import numpy as np m = len(word1) n = len(word2) dp = np.zeros((m+1,n+1),int) """ dp[i][j] 表示长度为i和j的字符串str1和str2之间的最小编辑距离,解题思路如下
if str1[m] == str2[n]:
dp[m][n] = dp[m-1][n-1]
else:
if str1 删除 ----> 将str1[m]删除
dp[m][n] = dp[m-1][n] + 1
if str1 替换 ----> 将str1[m]替换成str2[n]
dp[m][n] = dp[m-1][n-1] + 1
if str1 插入 ----> 在str1[m+1]处插入一个字符
dp[m][n] = dp[m][n-1] + 1
""" dp[0] = range(n + 1) # 表示str1为空字符串,最小编辑距离就等于str2的长度 dp[:,0] = range(m + 1) # 表示str2为空字符串,最小编辑距离就等于str1的长度 for i in range(1,m+1): for j in range(1,n+1): if word1[i-1] == word2[j-1]: # 第i个位置和第j个位置相同的话,则等于长度为i-1到长度为j-1的两个字符串的最小编辑距离 dp[i][j] = dp[i-1][j-1] else:# 三种状态下取最小值 dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) return dp[m][n]
18. 归并排序
def mergesort(seq): if len(seq) <= 1: return seq mid = len(seq) // 2 left = mergesort(seq[:mid]) right = mergesort(seq[mid:]) return merge(left, right)
def merge(left, right): result = [] i, j = 0, 0 while i < len(left) and j < len(right): if left[i] <= right[j]: result.append(left[i]) i += 1 else: result.append(right[j]) j += 1 result += left[i:] result += right[j:] return result
if __name__ == '__main__': seq = [4, 5, 7, 9, 7, 5, 1, 0, 7, -2, 3, -99, 6]print(mergesort(seq))
19. 循环链表及其头结点
class Solution(object): def detectCycle(self, head): """
:type head: ListNode
:rtype: ListNode
""" if head is None: return None faster, slower = head, head flag = False while faster.next is not None and faster.next.next is not None: faster = faster.next.next slower = slower.next if slower == faster: flag = True break if flag: slower = head while slower != faster: slower = slower.next faster = faster.next return slower else: return None
20. 最长连续上升子序列
class Solution(object): def findLengthOfLCIS(self, nums): """
:type nums: List[int]
:rtype: int
""" if not nums: return 0 if len(nums) == 1: return 1 res = 1 anchor = 1 for i in range(1,len(nums)): if nums[i] > nums[i-1]: anchor = anchor + 1 else: anchor = 1 res = max(res, anchor) return res
21. 最长上升子序列 (非连续)
def fun(nums): """
最长递增子序列
状态方程:dp[i]代表以第i个位置元素结尾的最长上升子序列,判断第i个位置时,需要比较前面的所有元素,若小于的话,则该元素可以作为一个中转点,把第i个位置拼接上去,长度加1
""" dp = [1] * (len(nums) + 1)
for i in range(len(nums)): for j in range(i): if nums[j] < nums[i]: dp[i] = max(dp[i], dp[j] + 1)
return max(dp)
print(fun([10, 9, 2, 5, 3, 7, 101, 18]))
22. 最长公共子序列
def longestCommonString(str1, str2): if len(str1) == 0 or len(str2) == 0: return 0
m = len(str1) n = len(str2)
dp = np.zeros((m + 1, n + 1))
for i in range(1, m + 1): for j in range(1, n + 1): if str1[i - 1] == str2[j - 1]: dp[i][j] = dp[i - 1][j - 1] + 1 else: dp[i][j] = max(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) return dp[-1][-1]
23. 最长上升子序列的个数
class Solution(object): def findNumberOfLIS(self, nums): """
:type nums: List[int]
:rtype: int
""" if not nums: return 0 dp = [1] * len(nums) count = [1] * len(nums) for i in range(len(nums)): for j in range(i): if nums[j] < nums[i]: if dp[j] + 1 > dp[i]: dp[i] = max(dp[i], dp[j] + 1) count[i] = count[j] elif dp[j] + 1 == dp[i]: count[i] += count[j] ans = 0 for i in range(len(dp)-1,-1,-1): if dp[i] == max(dp): ans += count[i] return ans
24. 最长连续序列
class Solution(object): def longestConsecutive(self, nums): """
用哈希表存储每个端点值对应连续区间的长度
若数已在哈希表中:跳过不做处理
若是新数加入:
取出其左右相邻数已有的连续区间长度 left 和 right
计算当前数的区间长度为:cur_length = left + right + 1
根据 cur_length 更新最大长度 max_length 的值
更新区间两端点的长度值
""" hash_dict = dict()
max_length = 0 for num in nums: if num not in hash_dict: left = hash_dict.get(num - 1, 0) right = hash_dict.get(num + 1, 0) print(left, right)
cur_length = 1 + left + right if cur_length > max_length: max_length = cur_length
hash_dict[num] = cur_length hash_dict[num - left] = cur_length hash_dict[num + right] = cur_length
return max_length
solution = Solution()print(solution.longestConsecutive([100, 4, 200, 1, 3, 2]))
25. 戳气球
class Solution: def maxCoins(self, nums: List[int]) -> int: n = len(nums) val = [1] + nums + [1]
@lru_cache(None) def getCoins(left, right): if left >= right - 1: return 0 best = 0 for mid in range(left + 1, right): total = val[left] * val[mid] * val[right] total += getCoins(left,mid) + getCoins(mid,right) best = max(best, total) return best
return getCoins(0,n+1)
26. 二叉树遍历
class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = Noneclass Solution: # 先序打印二叉树(递归) def preOrderTraverse(node): if node is None: return None print(node.val) preOrderTraverse(node.left) preOrderTraverse(node.right) # 先序打印二叉树(非递归) def preOrderTravese(node): stack = [node] while len(stack) > 0: print(node.val) if node.right is not None: stack.append(node.right) if node.left is not None: stack.append(node.left) node = stack.pop() # 中序打印二叉树(递归) def inOrderTraverse(node): if node is None: return None inOrderTraverse(node.left) print(node.val) inOrderTraverse(node.right) # 中序打印二叉树(非递归) def inOrderTraverse(node): stack = [] pos = node while pos is not None or len(stack) > 0: if pos is not None: stack.append(pos) pos = pos.left else: pos = stack.pop() print(pos.val) pos = pos.right # 后序打印二叉树(递归) def postOrderTraverse(node): if node is None: return None postOrderTraverse(node.left) postOrderTraverse(node.right) print(node.val) # 后序打印二叉树(非递归) # 使用两个栈结构 # 第一个栈进栈顺序:左节点->右节点->跟节点 # 第一个栈弹出顺序: 跟节点->右节点->左节点(先序遍历栈弹出顺序:跟->左->右) # 第二个栈存储为第一个栈的每个弹出依次进栈 # 最后第二个栈依次出栈 def postOrderTraverse(node): stack = [node] stack2 = [] while len(stack) > 0: node = stack.pop() stack2.append(node) if node.left is not None: stack.append(node.left) if node.right is not None: stack.append(node.right) while len(stack2) > 0: print(stack2.pop().val)
27. 二叉树的层序遍历
# BFS版本# class TreeNode(object):# def __init__(self, x):# self.val = x# self.left = None# self.right = None
class Solution(object): def levelOrder(self, root): """
:type root: TreeNode
:rtype: List[List[int]]
""" if not root: return [] res = [] queue = collections.deque() queue.append(root) while len(queue) > 0: length = len(queue) layer = [] for _ in range(length): cur = queue.popleft() layer.append(cur.val) if cur.left is not None: queue.append(cur.left) if cur.right is not None: queue.append(cur.right) res.append(layer) return res
# DFS版本# class TreeNode(object):# def __init__(self, x):# self.val = x# self.left = None# self.right = None
class Solution(object): def levelOrder(self, root): """
:type root: TreeNode
:rtype: List[List[int]]
""" res = [] self.level(root, 0, res) return res
def level(self, root, level, res): if not root: return if len(res) == level: res.append([]) res[level].append(root.val) if root.left: self.level(root.left, level + 1, res) if root.right: self.level(root.right, level + 1, res)
28. 不含连续1的非负整数
# dp[i]表示第i位满足要求的数目# 以7为例,dp[7] = dp[6] + '0' + dp[5] + '01'; 考虑第七位为0,问题转化为dp[6]的子问题,考虑第7位为1,第六位只能为0,则问题转化为求解dp[5]def solve(num): dp = [0] * 30 dp[0] = 1 dp[1] = 2 for i in range(2, 30): dp[i] = dp[i - 1] + dp[i - 2]
i = 30 pre = 0 res = 0
while i >= 0: if num & (1 << i): # 从左往右第一个为1的高位,相当于把改为置为0, 考虑后面所有的情况,也就是dp[i] res += dp[i] if pre == 1: # 如果出现相邻两个1的话,则将第二位1置为0,考虑后面的所有情况,也就是dp[i] res -= 1 # 这里减一主要是为了和保持格式统一,因为这里面已经包含了num在内了,所以后面先减1在最后加1保持不变,这种情况直接结束 break pre = 1 else: pre = 0 i -= 1 return res + 1
print(solve(7))
29. 构造二叉树
已知二叉树前序遍历和中序遍历,求后序遍历
class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None
class Solution: def reConstructBinaryTree(self, pre, tin): """
返回构造的TreeNode根节点
:param pre:
:param tin:
:return:
""" if not pre and not tin: return None root = TreeNode(pre[0]) tin_index = tin.index(pre[0]) # 查找性能优化,可以采用dict root.left = self.reConstructBinaryTree(pre[1:tin_index + 1], tin[0:tin_index]) root.right = self.reConstructBinaryTree(pre[tin_index + 1:], tin[tin_index + 1:]) return root
def PostTraversal(self, root): """
后序遍历
:param root:
:return:
""" if root is not None: self.PostTraversal(root.left) self.PostTraversal(root.right) print(root.val)
pre = [1, 2, 4, 7, 3, 5, 6, 8]tin = [4, 7, 2, 1, 5, 3, 8, 6]S = Solution()root = S.reConstructBinaryTree(pre, tin)S.PostTraversal(root)
# 加速版本class Solution: def buildTree(self, preorder, inorder): self.dic, self.po = {}, preorder for i in range(len(inorder)): self.dic[inorder[i]] = i return self.recur(0, 0, len(inorder) - 1)
def recur(self, pre_root, in_left, in_right): if in_left > in_right: return # 终止条件:中序遍历为空 root = TreeNode(self.po[pre_root]) # 建立当前子树的根节点 i = self.dic[self.po[pre_root]] # 搜索根节点在中序遍历中的索引,从而可对根节点、左子树、右子树完成划分。 root.left = self.recur(pre_root + 1, in_left, i - 1) # 开启左子树的下层递归 root.right = self.recur(i - in_left + pre_root + 1, i + 1, in_right) # 开启右子树的下层递归 return root # 返回根节点,作为上层递归的左(右)子节点
从中序与后序遍历序列构造二叉树
# Definition for a binary tree node.# class TreeNode(object):# def __init__(self, x):# self.val = x# self.left = None# self.right = Noneclass Solution(object): def buildTree(self, inorder, postorder): """
:type inorder: List[int]
:type postorder: List[int]
:rtype: TreeNode
""" if not postorder: return None root = TreeNode(postorder[-1]) n = inorder.index(root.val) root.left = self.buildTree(inorder[:n],postorder[:n]) root.right = self.buildTree(inorder[n+1:],postorder[n:-1]) return root
根据前序和后序遍历构造二叉树class Solution(object): def constructFromPrePost(self, pre, post): if not pre: return None root = TreeNode(pre[0]) if len(pre) == 1: return root
L = post.index(pre[1]) + 1 root.left = self.constructFromPrePost(pre[1:L+1], post[:L]) root.right = self.constructFromPrePost(pre[L+1:], post[L:-1]) return rootclass Solution(object): def constructFromPrePost(self, pre, post): def make(i0, i1, N): if N == 0: return None root = TreeNode(pre[i0]) if N == 1: return root
for L in xrange(N): if post[i1 + L - 1] == pre[i0 + 1]: break
root.left = make(i0 + 1, i1, L) root.right = make(i0 + L + 1, i1 + L, N - 1 - L) return root
return make(0, 0, len(pre))
30. 合并两个有序数组
class Solution(object): def merge(self, nums1, m, nums2, n): # 从后往前考虑 length = m + n - 1 m -= 1 n -= 1 while m >= 0 and n >= 0: if nums2[n] > nums1[m]: nums1[length] = nums2[n] n -= 1 else: nums1[length] = nums1[m] m -= 1 length -= 1 if n >= 0: nums1[:n+1] = nums2[:n+1]
31. 奇偶链表
# Definition for singly-linked list.# class ListNode(object):# def __init__(self, val=0, next=None):# self.val = val# self.next = nextclass Solution(object): def oddEvenList(self, head): """
:type head: ListNode
:rtype: ListNode
""" if not head: return head odd_head = odd = head even_head = even = head.next while odd.next and even.next: # print(odd,even) odd.next, even.next = odd.next.next, even.next.next odd, even = odd.next, even.next odd.next = even_head return odd_head
32. 冒泡排序优化版
def BubbleSort(numList): if not len(numList): return for i in range(len(numList)): isSwap = False j = len(numList) - 1 while j > i: # 初级优化,可以考虑从尾部开始,这样可以将以排好序的部分不再检查 if numList[j] < numList[j - 1]: numList[j], numList[j - 1] = numList[j - 1], numList[j] isSwap = True j -= 1 if not isSwap: # 通过设置boolean变量来判断某次循环是否没有出现交换,说明排序已完成 return numList return numList
print(BubbleSort([2, 3, 5, 4, 2, 1, 7, 3]))
33. 最长回文子串
def palindrome(s, i, j): while i >= 0 and j < len(s) and s[i] == s[j]: i -= 1 j += 1 return s[i + 1:j]
def solve(s): """
返回最长回文子串的其中之一,最大长度,所有结果,字典序最小
:param s:
:return:
""" res = "" resList = [] max_length = 1 for i in range(len(s)): s1 = palindrome(s, i, i) s2 = palindrome(s, i, i + 1) t = [] if len(s1) > len(s2): t.append(s1) mt = s1 elif len(s1) == len(s2): t.extend([s1, s2]) mt = s1 else: t.append(s2) mt = s2
if len(res) <= len(mt): resList.extend(t) res = mt max_length = max(max_length, len(res)) resList = [i for i in resList if len(i) == max_length] # 移除长度更短的结果 resList = sorted([i for i in resList if len(i) == max_length]) # 返回字典序最小的那个 return res, resList, max_length, resList[0]
print(solve("bbbaaacccddd"))
34. 回文链表
def isPalindrome(self, head): vals = [] current_node = head while current_node is not None: vals.append(current_node.val) current_node = current_node.next return vals == vals[::-1]
35. 高楼扔鸡蛋
# 解法一:def superEggDrop(self, K: int, N: int) -> int: memo = dict() def dp(K, N): if K == 1: return N if N == 0: return 0 if (K, N) in memo: return memo[(K, N)] # for 1 <= i <= N: # res = min(res, # max( # dp(K - 1, i - 1), # dp(K, N - i) # ) + 1 # )
res = float('INF') # 用二分搜索代替线性搜索 lo, hi = 1, N while lo <= hi: mid = (lo + hi) // 2 broken = dp(K - 1, mid - 1) # 碎 not_broken = dp(K, N - mid) # 没碎 # res = min(max(碎,没碎) + 1) if broken > not_broken: hi = mid - 1 res = min(res, broken + 1) else: lo = mid + 1 res = min(res, not_broken + 1)
memo[(K, N)] = res return res return dp(K, N)# 解法二class Solution(object): def superEggDrop(self, K, N): """
f(T,K)代表有T次试验,K个鸡蛋最高能达到的楼层高度N
状态方程:f(T,K) = f(T-1,K) + f(T-1,K-1) + 1
- 如果鸡蛋没有碎,则说明这层上面还可以有f(T-1,K)层
- 如果鸡蛋碎了,则说明这层下面还可以有f(T-1,K-1)层
""" if N == 1: return 1 f = [[0] * (K + 1) for _ in range(N + 1)] for i in range(1, K + 1): f[1][i] = 1 ans = -1 for i in range(2, N + 1): for j in range(1, K + 1): f[i][j] = 1 + f[i - 1][j - 1] + f[i - 1][j] if f[i][K] >= N: ans = i break return ans# 解法三:最快的代码def superEggDrop(K, N): """
K个鸡蛋,尝试一次能到达的楼层数N,类似于压缩二维的DP数组
dp[k] += dp[k - 1] + 1
""" dp = [0] * (K + 1) res = 0 while dp[K] < N: for k in range(K, 0, -1): dp[k] += dp[k - 1] + 1 res += 1
return res
superEggDrop(3, 10)
36. 最长上升子序列(字典序最小)
import bisect
n = int(input())nums = list(map(int, input().split()))dp, helper, length = [1] * n, [nums[0]], 1# helper 长度为i的LIS末尾的数# dp 存放以i结尾的序列长度
for i in range(1, n): if nums[i] > helper[-1]: length += 1 dp[i] = length helper.append(nums[i]) else: # 查找helper数组中第一个大于等于nums[i]的数并替换它 pos = bisect.bisect(helper, nums[i]) dp[i] = pos + 1 helper[pos] = nums[i]
end, length = helper[-1], max(dp)index = nums.index(end)res = []
# 回退查找字典序最小的while index >= 0: if not res or (nums[index] < res[-1] and dp[index] == length): res.append(nums[index]) length -= 1 if not length: break index -= 1print(' '.join(map(str, res[::-1])))
37. 最长上升子序列(所有序列)
from copy import deepcopy
nums = [10, 9, 2, 5, 3, 7, 101, 18]
length = len(nums)
dp = [1] * length
max_length = 1allSeqList = []for i in range(length): local = [] index = -1 for j in range(i): if nums[i] > nums[j]: if dp[j] + 1 > dp[i]: local.clear() index = j local.extend(deepcopy(allSeqList[j])) for item in local: item.append(nums[i]) dp[i] = dp[j] + 1 elif dp[j] + 1 == dp[i]: more = deepcopy(allSeqList[j]) for item in more: item.append(nums[i]) local.extend(more)
if index == -1: tmp = [nums[i]] local.append(tmp)
allSeqList.append(deepcopy(local)) max_length = max(dp[i], max_length)
res = []for i in range(length): if dp[i] == max_length: res.extend(allSeqList[i])print(res)
38. 所有的递增子序列
def findSubsequences(nums): if not nums: return [] pres = {(nums[0],)} for j in pres: print(j[-1]) for i in nums[1:]: print({j + (i,) for j in pres if j[-1] <= i}) pres.update({j + (i,) for j in pres if j[-1] <= i}) pres.add((i,)) return [list(i) for i in pres if len(i) > 1]
print(findSubsequences([4, 6, 7, 7]))
39. 连续子数组和为K的个数
from collections import defaultdict
def subArraySum(nums, k): n = len(nums) dict_nums = defaultdict(int) dict_nums[0] = 1 ans = 0 sum_i = 0 for i in range(n): sum_i += nums[i] sum_j = sum_i - k if dict_nums[sum_j]: ans += dict_nums[sum_j] dict_nums[sum_i] += 1
return ans
print(subArraySum([1, 1, 1], 2))
40. 全排列
from copy import deepcopy
class Combination(object): def __init__(self, nums, track): self.res = [] self.nums = nums self.n = len(nums) self.track = track
def backTrace(self): if self.n == len(self.track): self.res.append(deepcopy(self.track)) return for i in range(self.n): if self.nums[i] in self.track: continue self.track.append(self.nums[i]) self.backTrace() self.track.remove(self.nums[i])
combination = Combination([1, 2, 3], [])combination.backTrace()print(combination.res)
41. 区间交集
class Solution(object): def intervalIntersection(self, A, B): """
:type A: List[List[int]]
:type B: List[List[int]]
:rtype: List[List[int]]
""" n = len(A) m = len(B) i, j = 0, 0 res = [] while i < n and j < m: a1, a2 = A[i][0], A[i][1] b1, b2 = B[j][0], B[j][1] # 区间有交集 if b2 >= a1 and b1 <= a2: res.append([max(a1,b1),min(a2,b2)]) # 指针移动 if a2 >= b2: j += 1 else: i += 1 return res
42. 洗牌算法
from random import randint
def shuffle(arr): n = len(arr) for i in range(n): rand = randint(i, n - 1) arr[i], arr[rand] = arr[rand], arr[i] return arr
43. 滑动谜题
from collections import defaultdict, deque
class Solution(object): def slidingPuzzle(self, board): start = ''.join(map(str, board[0])) + ''.join(map(str, board[1])) target = "123450" queue = deque([start]) visited = defaultdict(int) neighbor = [[1, 3], [0, 4, 2], [1, 5], [0, 4], [3, 1, 5], [4, 2]] visited[start] = 1 step = 0 while queue: for i in range(len(queue)): cur = queue.popleft() if target == cur: return step idx = cur.index('0') for adj in neighbor[idx]: new_board = [i for i in cur] new_board[adj], new_board[idx] = new_board[idx], new_board[adj] new_board = ''.join(new_board) if not visited[new_board]: queue.append(new_board) visited[new_board] = 1 step += 1 return -1
44. 高效素数计算
import math
def SieveOfEratosthenes(n): is_prime = [True for _ in range(n)] for i in range(2, int(math.sqrt(n)) + 1): if is_prime[i]: for j in range(i ** 2, n, i): is_prime[j] = False cnt = 0 for i in range(2, n): if is_prime[i]: cnt += 1 print(i) return cnt
n = 30print(SieveOfEratosthenes(n))
45. 接雨水问题
class Solution(object): def trap(self, height): """
:type height: List[int]
:rtype: int
""" if not height: return 0 n = len(height) l_max = height[0] r_max = height[-1] left = 0 right = n - 1 ans = 0 # ans = min(l_max, r_max) + height[i] while left <= right: l_max = max(l_max, height[left]) r_max = max(r_max, height[right]) if l_max < r_max: ans += l_max - height[left] left += 1 else: ans += r_max - height[right] right -= 1 return ans
46. 最长回文子序列的长度
def solve(s): """
dp[i][j] = s[i....j]最长回文子序列的长度
:param s:
:return:
""" n = len(s) dp = [[0] * n for _ in range(n)] for i in range(n): dp[i][i] = 1 # 先从底向上推,再从左向右推 for i in range(n - 1, -1, -1): for j in range(i + 1, n): if s[i] == s[j]: dp[i][j] = dp[i + 1][j - 1] + 2 else: dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]) return dp[0][n - 1]
print(solve("bbbab"))
47. 跳跃游戏
def jump(nums): n = len(nums) end = 0 farthest = 0 jumps = 0 for i in range(n - 1): farthest = max(nums[i] + i, farthest) if end == i: end = farthest jumps += 1 return jumps
print(jump([2, 3, 1, 1, 4]))
48. k个一组反转链表
class Solution(object): def reverseKGroup(self, head, k): """
k个一组反转链表
""" if not head: return None a, b = head, head for i in range(k): if not b: return head b = b.next newHead = self.reverse(a, b) a.next = self.reverseKGroup(b, k) return newHead
def reverse(self, a, b): """
反转节点a到节点b之间的节点
:param a:
:param b:
:return:
""" pre = None cur = a while cur != b: t = cur.next cur.next = pre pre = cur cur = t return pre
49. 判断括号的合法性
def isValid(s): left = [] for i in s: if i in ['(', '{', '[']: left.append(i) else: if left and leftOf(i) == left[-1]: left.pop(-1) else: return False
return True if not left else False
def leftOf(c): if c == '}': return '{' elif c == ')': return '(' else: return '['
print(isValid("()[]{}"))
50. 寻找缺失和重复的元素
def findErrorNums(nums): n = len(nums) dup = -1 for i in range(n): index = abs(nums[i]) - 1 if nums[index] < 0: dup = abs(nums[i]) else: nums[index] *= -1 missing = -1 for i in range(n): if nums[i] > 0: missing = i + 1
return dup, missing
print(findErrorNums([0, 4, 1, 4, 2]))
51. 无限序列中随机抽取元素
import random
def solve(head, k): """
无限序列中随机抽取元素
:param head:
:param k:
:return:
""" res = [] p = head for i in range(k): if not p: break res[i] = p.val p = p.next
i = k while p: i += 1 j = random.randint(0, i) if j < k: res[j] = p.val p = p.next return res
52. 高效判定子序列
import bisectfrom collections import defaultdict
def isSubsequence(s, t): m = len(s) n = len(t) index = defaultdict(list) for i in range(n): index[t[i]].append(i) j = 0 for i in range(m): if not index[s[i]]: return False pos = bisect.bisect_left(index[s[i]], j) if pos == len(index[s[i]]): return False j += index[s[i]][pos] + 1 return True
print(isSubsequence("abc", "ahbgdc"))
53. 并查集
class UF(object): """
并查集算法
"""
def __init__(self, n): self.count = n self.parent = [i for i in range(n)] self.size = [1] * n
def union(self, p, q): rootP = self.find(p) rootQ = self.find(q)
if rootP == rootQ: return
# 优化做法把小树接到大树下面 if self.size[rootP] > self.size[rootQ]: self.parent[rootQ] = rootP self.size[rootP] += self.size[rootQ] else: self.parent[rootP] = rootQ self.size[rootQ] += self.size[rootP]
self.count -= 1
def find(self, x): while self.parent[x] != x: # 路径压缩 self.parent[x] = self.parent[self.parent[x]] x = self.parent[x] return x
def connected(self, p, q): rootP = self.find(p) rootQ = self.find(q) return rootP == rootQ
def count(self): return self.count
class Solution(object): def solve(self, board): if not board: return m = len(board) n = len(board[0]) uf = UF(m * n + 1) dummy = m * n for i in range(m): if board[i][0] == 'O': uf.union(i * n, dummy) if board[i][n - 1] == 'O': uf.union(i * n + n - 1, dummy)
for i in range(n): if board[0][i] == 'O': uf.union(i, dummy) if board[m - 1][i] == 'O': uf.union(n * (m - 1) + i, dummy)
direction = [[1, 0], [-1, 0], [0, 1], [0, -1]] for i in range(1, m - 1): for j in range(n - 1): if board[i][j] == 'O': for k in range(4): x = i + direction[k][0] y = j + direction[k][1] if board[x][y] == 'O': uf.union(x * n + y, i * n + j)
for i in range(1, m - 1): for j in range(1, n - 1): if not uf.connected(dummy, i * n + j): board[i][j] = 'X'
return board
- END -