当前位置:   article > 正文

算法试题(Python实现)dfs、矩阵路径_python dfs

python dfs

目录

1. 分糖果问题(贪心思想)

2. 主持人调度(二)(贪心思想)

3. N皇后问题(递归)

4. 岛屿数量(dfs)

5. 设计LRU缓存结构(哈希表+双向链表)

6. 设计LFU缓存结构(双哈希表)

7. 螺旋矩阵(边界模拟法)

8. 顺时针旋转矩阵(倒置翻转法)

9. 不同路径的数目(一)

10. 矩阵最长递增路径(dfs+DP)

11. 矩阵的最小路径和

12. 编辑距离(一)

13. ​​​​​​​旋转数组(平移数组:三次翻转法)


1. 分糖果问题(贪心思想)

单独遍历两次,先从左往右遍历(右边大的+1),再从右往左遍历(左边大的+1)

  1. class Solution:
  2. def candy(self , arr: List[int]) -> int:
  3. # 记录每个位置的糖果数,每个孩子为默认为1
  4. nums = [1] * len(arr)
  5. # 从左到右遍历
  6. for i in range(1, len(arr)):
  7. # 如果右边大,则该位置糖果数为左边基础上加一
  8. if arr[i-1] < arr[i]:
  9. nums[i] = nums[i-1] + 1
  10. res = nums[len(arr) - 1]
  11. # 从右到左遍历
  12. for i in range(len(arr)-2, -1, -1):
  13. # 如果左边大且糖果数小,则该位置糖果数为右边基础上加一
  14. if arr[i] > arr[i+1] and nums[i] <= nums[i+1]:
  15. nums[i] = nums[i+1] + 1
  16. res += nums[i]
  17. return res

2. 主持人调度(二)(贪心思想)

排序+遍历(新开始的节目大于等于上一轮结束的时间,主持人不变,否则主持人+1)

  1. class Solution:
  2. def minmumNumberOfHost(self , n: int, startEnd: List[List[int]]) -> int:
  3. start = []
  4. end = []
  5. for i in range(n):
  6. start.append(startEnd[i][0])
  7. end.append(startEnd[i][1])
  8. start.sort()
  9. end.sort()
  10. res = 0
  11. j = 0
  12. for i in range(n):
  13. # 新开始的节目大于等于上一轮结束的时间,主持人不变
  14. if start[i] >= end[j]:
  15. j += 1
  16. else:
  17. # 主持人+1
  18. res += 1
  19. return res

3. N皇后问题(递归)

  1. class Solution:
  2. # 判断皇后是否符合条件
  3. def isValid(self, pos: List[int], row: int, col: int):
  4. # 遍历记录过的行
  5. for i in range(row):
  6. if row == i or col == pos[i] or abs(row-i) == abs(col-pos[i]):
  7. return False
  8. return True
  9. # 递归查找皇后种类
  10. def recursion(self, n: int, row: int, pos: List[int], res: int):
  11. if row == n:
  12. res += 1
  13. return res
  14. for i in range(n):
  15. if self.isValid(pos, row, i):
  16. pos[row] = i
  17. res = self.recursion(n, row + 1, pos, res)
  18. return res
  19. def Nqueen(self , n: int) -> int:
  20. res = 0
  21. # 下标为行号,元素为列号,记录皇后位置
  22. pos = [0]*n
  23. # 递归
  24. result = self.recursion(n, 0, pos, res)
  25. return result

4. 岛屿数量(dfs)

  1. class Solution:
  2. # 深度优先遍历
  3. def dfs(self, grid: List[List[chr]], i: int, j: int):
  4. n = len(grid)
  5. m = len(grid[0])
  6. grid[i][j] = '0'
  7. if i - 1 >= 0 and grid[i-1][j] == '1':
  8. self.dfs(grid, i-1, j)
  9. if i + 1 < n and grid[i+1][j] == '1':
  10. self.dfs(grid, i+1, j)
  11. if j - 1 >= 0 and grid[i][j-1] == '1':
  12. self.dfs(grid, i, j-1)
  13. if j + 1 < m and grid[i][j+1] == '1':
  14. self.dfs(grid, i, j+1)
  15. def solve(self , grid: List[List[str]]) -> int:
  16. n = len(grid)
  17. if n == 0: return 0
  18. m = len(grid[0])
  19. count = 0
  20. for i in range(n):
  21. for j in range(m):
  22. if grid[i][j] == '1':
  23. count += 1
  24. self.dfs(grid, i, j)
  25. return count

5. 设计LRU缓存结构(哈希表+双向链表)

使用数组实现

  1. class Solution:
  2. def __init__(self, capacity: int):
  3. self.capacity = capacity
  4. self.q = []
  5. def get(self, key: int) -> int:
  6. flag = True
  7. for i in range(len(self.q)):
  8. if self.q[i][0] == key:
  9. res = self.q[i][1]
  10. self.q.append(self.q.pop(i))
  11. flag = False
  12. break
  13. return -1 if flag else res
  14. def set(self, key: int, value: int) -> None:
  15. flag = True
  16. hasKey = False
  17. if len(self.q) >= self.capacity:
  18. for i in range(len(self.q)):
  19. if self.q[i][0] == key:
  20. self.q.pop(i)
  21. flag = False
  22. break
  23. if flag:
  24. self.q.pop(0)
  25. for i in range(len(self.q)):
  26. if self.q[i][0] == key:
  27. self.q[i][1] = value
  28. hasKey = True
  29. if not hasKey:
  30. self.q.append([key, value])
  31. return None

使用双向链表+双向链表实现。用哈希表的key值对应链表的节点。

  1. # 构建双向链表结点
  2. class Node:
  3. def __init__(self, key, value):
  4. self.key = key
  5. self.value = value
  6. self.pre = None
  7. self.next = None
  8. class Solution:
  9. # 约定:链表尾的元素最新
  10. def __init__(self, capacity: int):
  11. self.capacity = capacity
  12. # 双向链表头尾
  13. self.head = Node(-1,-1)
  14. self.tail = Node(-1,-1)
  15. self.head.next = self.tail
  16. self.tail.pre = self.head
  17. # 哈希表记录Node
  18. self.map = dict()
  19. # 获得当前大小
  20. def getSize(self) -> int:
  21. cur = self.head.next
  22. res = 0
  23. while cur != self.tail:
  24. cur = cur.next
  25. res += 1
  26. return res
  27. # 表尾插入新元素
  28. def insert(self, node: Node):
  29. node.pre = self.tail.pre
  30. node.next = self.tail
  31. self.tail.pre.next = node
  32. self.tail.pre = node
  33. # 移至表尾
  34. def moveToTail(self, node: Node):
  35. node.pre.next = node.next
  36. node.next.pre = node.pre
  37. self.insert(node)
  38. # 移除表头元素
  39. def moveHead(self):
  40. self.map.pop(self.head.next.key)
  41. self.head.next.next.pre = self.head
  42. self.head.next = self.head.next.next
  43. def get(self, key: int) -> int:
  44. res = -1
  45. if key in self.map:
  46. res = self.map[key].value
  47. self.moveToTail(self.map[key])
  48. return res
  49. def set(self, key: int, value: int) -> None:
  50. if key in self.map:
  51. self.moveToTail(self.map[key])
  52. self.map[key].value = value
  53. else:
  54. if self.getSize() >= self.capacity:
  55. self.moveHead()
  56. node = Node(key, value)
  57. self.map[key] = node
  58. self.insert(node)

6. 设计LFU缓存结构(双哈希表)

  1. import collections
  2. class Node:
  3. def __init__(self, freq, key, val):
  4. self.freq = freq
  5. self.key = key
  6. self.val = val
  7. class Solution:
  8. def __init__(self):
  9. #记录剩余空间
  10. self.size = 0
  11. #key到双向链表节点的哈希表
  12. self.mp = dict()
  13. #频率到链表的哈希表
  14. self.freq_mp = dict(collections.deque())
  15. #记录当前最小频次
  16. self.min_freq = 0
  17. #调用函数时更新频率或者val值
  18. def update(self, node: Node, key: int, value: int):
  19. #找到频率
  20. freq = node.freq
  21. #原频率中删除该节点
  22. self.freq_mp[freq].remove(node)
  23. #哈希表中该频率已无节点,直接删除
  24. if len(self.freq_mp[freq]) == 0:
  25. self.freq_mp.pop(freq)
  26. #若当前频率为最小,最小频率加1
  27. if self.min_freq == freq:
  28. self.min_freq += 1
  29. #插入频率加一的双向链表表头,链表中对应:freq key value
  30. node = Node(freq + 1, key, value)
  31. if freq + 1 not in self.freq_mp:
  32. self.freq_mp[freq + 1] = collections.deque()
  33. self.freq_mp[freq + 1].appendleft(node)
  34. self.mp[key] = self.freq_mp[freq + 1][0]
  35. #set操作函数
  36. def set(self, key:int, value: int):
  37. #在哈希表中找到key值
  38. if key in self.mp:
  39. #若是哈希表中有,则更新值与频率
  40. self.update(self.mp[key], key, value)
  41. else:
  42. #哈希表中没有,即链表中没有
  43. if self.size == 0:
  44. #满容量取频率最低且最早的删掉
  45. oldnode = self.freq_mp[self.min_freq].pop()
  46. #频率哈希表的链表中删除
  47. if len(self.freq_mp[self.min_freq]) == 0:
  48. self.freq_mp.pop(self.min_freq)
  49. #链表哈希表中删除
  50. self.mp.pop(oldnode.key)
  51. #若有空闲则直接加入,容量减1
  52. else:
  53. self.size -= 1
  54. #最小频率置为1
  55. self.min_freq = 1
  56. node = Node(1, key, value)
  57. if 1 not in self.freq_mp:
  58. self.freq_mp[1] = collections.deque()
  59. self.freq_mp[1].appendleft(node)
  60. #哈希表key值指向链表中该位置
  61. self.mp[key] = self.freq_mp[1][0]
  62. #get操作函数
  63. def get(self, key: int) -> int:
  64. res = -1
  65. #查找哈希表
  66. if key in self.mp:
  67. node = self.mp[key]
  68. #根据哈希表直接获取值
  69. res = node.val
  70. #更新频率
  71. self.update(node, key, res)
  72. return res
  73. def LFU(self , operators: List[List[int]], k: int) -> List[int]:
  74. res = []
  75. #构建初始化连接
  76. #链表剩余大小
  77. self.size = k
  78. #遍历所有操作
  79. for i in range(len(operators)):
  80. op = operators[i]
  81. if op[0] == 1:
  82. #set操作
  83. self.set(op[1], op[2])
  84. else:
  85. #get操作
  86. res.append(self.get(op[1]))
  87. return resnd(self.get(op[1]))
  88. return res

7. ​​​​​​​螺旋矩阵(边界模拟法)

  1. class Solution:
  2. def spiralOrder(self , matrix: List[List[int]]) -> List[int]:
  3. res = []
  4. n = len(matrix)
  5. if n == 0: return res
  6. # 上下左右边界
  7. left = 0
  8. right = len(matrix[0]) - 1
  9. up = 0
  10. down = n - 1
  11. while left <= right and up <= down:
  12. # 上边界的从左到右
  13. for i in range(left, right + 1):
  14. res.append(matrix[up][i])
  15. # 上边界下移
  16. up += 1
  17. if up > down: break
  18. # 右边界的从上到下
  19. for i in range(up, down + 1):
  20. res.append(matrix[i][right])
  21. # 右边界左移
  22. right -= 1
  23. if left > right: break
  24. # 下边界的从右到左
  25. for i in range(right, left - 1, -1):
  26. res.append(matrix[down][i])
  27. # 下边界上移
  28. down -= 1
  29. if up > down: break
  30. # 左边界的从下到上
  31. for i in range(down, up - 1, -1):
  32. res.append(matrix[i][left])
  33. # 左边界右移
  34. left += 1
  35. if left > right:
  36. break
  37. return res

8. 顺时针旋转矩阵(倒置翻转法)

  1. class Solution:
  2. def rotateMatrix(self , mat: List[List[int]], n: int) -> List[List[int]]:
  3. # 矩阵转置
  4. for i in range(n):
  5. for j in range(i):
  6. # 交换上三角与下三角对应的元素
  7. mat[i][j], mat[j][i] = mat[j][i], mat[i][j]
  8. # 每行翻转
  9. for i in range(n):
  10. mat[i].reverse()
  11. return mat

9. 不同路径的数目(一)

  1. class Solution:
  2. def uniquePaths(self , m: int, n: int) -> int:
  3. dp = [[0] * (n+1) for i in range(m + 1)]
  4. for i in range(1, m + 1):
  5. for j in range(1, n + 1):
  6. if i == 1:
  7. dp[i][j] = 1
  8. continue
  9. if j == 1:
  10. dp[i][j] = 1
  11. continue
  12. dp[i][j] = dp[i-1][j] + dp[i][j-1]
  13. return dp[m][n]

10. 矩阵最长递增路径(dfs+DP)

  1. class Solution:
  2. global dirs
  3. dirs = [[-1, 0], [1, 0], [0, -1], [0, 1]]
  4. global n, m
  5. # 深度优先搜索,返回最大单元格数
  6. def dfs(self, matrix: List[List[int]], dp: List[List[int]], i: int, j: int):
  7. if dp[i][j] != 0:
  8. return dp[i][j]
  9. dp[i][j] += 1
  10. for k in range(4):
  11. nexti = i + dirs[k][0]
  12. nextj = j + dirs[k][1]
  13. if nexti >= 0 and nexti < n and nextj >= 0 and nextj < m and matrix[nexti][nextj] > matrix[i][j]:
  14. dp[i][j] = max(dp[i][j], self.dfs(matrix, dp, nexti, nextj) + 1)
  15. return dp[i][j]
  16. def solve(self , matrix: List[List[int]]) -> int:
  17. global n, m
  18. if len(matrix) == 0 or len(matrix[0]) == 0:
  19. return 0
  20. res = 0
  21. n = len(matrix)
  22. m = len(matrix[0])
  23. dp = [[0 for col in range(m)] for row in range(n)]
  24. for i in range(n):
  25. for j in range(m):
  26. res = max(res, self.dfs(matrix, dp, i, j))
  27. return res

11. 矩阵的最小路径和

  1. class Solution:
  2. def minPathSum(self, matrix: List[List[int]]) -> int:
  3. n = len(matrix)
  4. # 因为n,m均大于等于1
  5. m = len(matrix[0])
  6. # dp[i][j]表示以当前i,j位置为终点的最短路径长度
  7. dp = [[0] * (m + 1) for i in range(n + 1)]
  8. dp[0][0] = matrix[0][0]
  9. # 处理第一列
  10. for i in range(1, n):
  11. dp[i][0] = matrix[i][0] + dp[i - 1][0]
  12. # 处理第一行
  13. for j in range(1, m):
  14. dp[0][j] = matrix[0][j] + dp[0][j - 1]
  15. # 其他按照公式来
  16. for i in range(1, n):
  17. for j in range(1, m):
  18. if dp[i - 1][j] > dp[i][j - 1]:
  19. dp[i][j] = matrix[i][j] + dp[i][j - 1]
  20. else:
  21. dp[i][j] = matrix[i][j] + dp[i - 1][j]
  22. return dp[n - 1][m - 1]

12. 编辑距离(一)

  1. class Solution:
  2. def editDistance(self, str1: str, str2: str) -> int:
  3. n1 = len(str1)
  4. n2 = len(str2)
  5. # dp[i][j]表示到str1[i]和str2[j]为止的子串需要的编辑距离
  6. dp = [[0] * (n2 + 1) for i in range(n1 + 1)]
  7. # 初始化边界
  8. for i in range(1, n1 + 1):
  9. dp[i][0] = dp[i - 1][0] + 1
  10. for i in range(1, n2 + 1):
  11. dp[0][i] = dp[0][i - 1] + 1
  12. # 遍历第一个字符串的每个位置
  13. for i in range(1, n1 + 1):
  14. # 对应第二个字符串每个位置
  15. for j in range(1, n2 + 1):
  16. # 若是字符相同,此处不用编辑
  17. if str1[i - 1] == str2[j - 1]:
  18. # 直接等于二者前一个的距离
  19. dp[i][j] = dp[i - 1][j - 1]
  20. else:
  21. # 选取最小的距离加上此处编辑距离1
  22. dp[i][j] = (
  23. min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i][j - 1])) + 1
  24. )
  25. return dp[n1][n2]

13. ​​​​​​​旋转数组(平移数组:三次翻转法)

  1. class Solution:
  2. def solve(self , n: int, m: int, a: List[int]) -> List[int]:
  3. # 取余,因为每次长度为n的旋转数组相当于没有变化
  4. m = m % n
  5. # 第一次 逆转全部数组元素
  6. a.reverse()
  7. b = a[:m]
  8. # 第二次 逆转开头m个
  9. b.reverse()
  10. c = a[m:]
  11. # 第三次 只逆转结尾n-m个
  12. c.reverse()
  13. a[:m] = b
  14. a[m:] = c
  15. return a

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/462512
推荐阅读
相关标签
  

闽ICP备14008679号