DFS-困难
1 124. 二叉树中的最大路径和 https://leetcode-cn.com/problems/binary-tree-maximum-path-sum/
考点:
1、后续遍历,根据左右节点和当前节点的值,判断当前节点最大路径的值
2、一个需要注意点是,左右节点+当前节点作为步骤1之外一个单独的路径(红色字体部分代码)
# 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:
def set_val(self, value):
if value > self.max_num:
self.max_num = value
def helper(self, root):
if root == None:
return None
left_max = self.helper(root.left)
right_max = self.helper(root.right)
# 叶子节点
if left_max == None and right_max == None:
self.set_val(root.val)
return root.val
elif left_max == None:
value = max(right_max + root.val, root.val)
self.set_val(value)
return value
elif right_max == None:
value = max(left_max + root.val, root.val)
self.set_val(value)
return value
else:
value = max(left_max + root.val, right_max + root.val, root.val)
value2 = left_max + right_max + root.val
if value > value2:
self.set_val(value)
else:
self.set_val(value2)
return value
def maxPathSum(self, root: TreeNode) -> int:
# 后序遍历, 则当前节点最大路径为 max(左右+当前节点, 左+当前节点,右+当前节点, 当前节点)
self.max_num = root.val
self.helper(root)
return self.max_num
2 980. 不同路径 III https://leetcode-cn.com/problems/unique-paths-iii/
考点:
1、深度搜索,碰到非-1值迭代搜索路径; 结束条件为 碰到结束点,满足条件是走过了全路径,即走过路径长度等于全路径长度
class Solution: def helper(self, grid, cur, cur_path): print(cur, self.end) if cur == self.end: if len(cur_path) == self.path_len: self.result.append(cur_path) return tmp_i, tmp_j = cur for i,j in [(tmp_i+1, tmp_j), (tmp_i -1, tmp_j), (tmp_i, tmp_j +1), (tmp_i, tmp_j -1)]: if 0 <= i < self.row and 0 <= j < self.col and not grid[i][j] == -1 and (i, j) not in cur_path: tmp_cur_path = list(cur_path) tmp_cur_path.append((i, j)) self.helper(grid, (i, j), tmp_cur_path) def uniquePathsIII(self, grid: List[List[int]]) -> int: self.row = len(grid) self.col = len(grid[0]) start = None self.end = None blocked = 0 for i in range(self.row): for j in range(self.col): if grid[i][j] == 1: start = (i, j) elif grid[i][j] == -1: blocked += 1 elif grid[i][j] == 2: self.end = (i, j) self.path_len = self.row * self.col - blocked # DFS self.result = [] self.helper(grid, start, [start]) return len(self.result)
3. 839. 相似字符串组 https://leetcode-cn.com/problems/similar-string-groups/
考点: 深度搜索
class Solution: def fulfil(self, str1, str_list): str_len = len(str1) for str2 in str_list: diff = 0 for i in range(str_len): if not str1[i] == str2[i]: diff += 1 if diff == 2 or diff == 0: return True return False def helper(self, A): if len(A) == 0: return found = False tmp_A = list(A) for s_str in A: for result in self.results: if self.fulfil(s_str, result): found = True result.append(s_str) tmp_A.remove(s_str) if not found: tmp_str = A[0] self.results.append([tmp_str]) tmp_A.remove(tmp_str) self.helper(tmp_A) def numSimilarGroups(self, A: List[str]) -> int: self.results = [] self.helper(A) return len(self.results)
考虑优化,设置2级结果,已经遍历完全的组不参与遍历,继续超时
class Solution: def fulfil(self, str1, str_list): str_len = len(str1) for str2 in str_list: diff = 0 for i in range(str_len): if not str1[i] == str2[i]: diff += 1 if diff == 2 or diff == 0: return True return False def helper(self, A): if len(A) == 0: self.results.append(self.results_tmp) self.results_tmp = [] return found = False tmp_A = list(A) for s_str in A: if self.fulfil(s_str, self.results_tmp): found = True self.results_tmp.append(s_str) tmp_A.remove(s_str) if not found: tmp_str = A[0] if self.results_tmp: self.results.append(self.results_tmp) self.results_tmp = [] tmp_A.remove(tmp_str) self.results_tmp.append(tmp_str) self.helper(tmp_A) def numSimilarGroups(self, A: List[str]) -> int: self.results = [] self.results_tmp = [] self.helper(A) return len(self.results)
想来想去,该种方法都需要 n *n 循环
j继续优化,把字符窜分成一个个小类计算,还是时间超时,只能跑31 / 63 个通过测试用例
class Solution: def fulfil(self, str1, str_list): str_len = len(str1) for str2 in str_list: diff = 0 for i in range(str_len): if not str1[i] == str2[i]: diff += 1 if diff == 2 or diff == 0: return True return False def helper(self, A): if len(A) == 0: return # 获取字符窜 tmp_str = A[0] ori_list = [tmp_str] # 获取相似字符窜,删除 A.remove(tmp_str) while ori_list: found = False tmp_list = [] tmp_A = list(A) for a in tmp_A: if self.fulfil(a, ori_list): found = True tmp_list.append(a) A.remove(a) ori_list = list(tmp_list) if not found: break # print(A) self.results += 1 # 迭代 self.helper(A) def numSimilarGroups(self, A: List[str]) -> int: # 时间超时,性能优化问题,首先想到是dict, 所以问题就变成使用什么样的key self.results = 0 A_dict = collections.defaultdict(set) for a in A: A_dict["".join(sorted(a))].add(a) # print(A_dict) for value in A_dict.values(): self.helper(list(value)) # self.helper(A) return self.results
继续使用并查集优化,多通过一个用例,忧伤(32 / 63 个通过测试用例)
class Solution: def search(self, a, ilist): if ilist[a] != a: ilist[a] = self.search(ilist[a], ilist) return ilist[a] def union(self, a, b, ilist): aa = self.search(a, ilist) bb = self.search(b, ilist) # print("********") # print(a, aa) # print(b, bb) # print("%%%%%%%%%") if aa > bb: ilist[aa] = bb else: ilist[bb] = aa # print("****", ilist) def match(self, a, b): diff_len = 0 for i in range(len(a)): if not a[i] == b[i]: diff_len += 1 if diff_len == 2: return True return False def helper(self, str_list): if len(str_list) == 0: return len_A = len(str_list) ilist = [] ilist_dict = dict() for i in range(len_A): ilist.append(i) ilist_dict[str_list[i]] = i # print(ilist) # print(ilist_dict) for i in range(len_A-1): for j in range(i+1, len_A): if self.match(str_list[i], str_list[j]): # print("&", ilist) # print(i, j) self.union(i ,j, ilist) # print(ilist) for i in range(len(ilist)): self.search(i, ilist) self.results += len(set(ilist)) def numSimilarGroups(self, A: List[str]) -> int: # 时间超时,性能优化问题,首先想到是dict, 所以问题就变成使用什么样的key self.results = 0 A_dict = collections.defaultdict(set) for a in A: A_dict["".join(sorted(a))].add(a) # print(A_dict) for value in A_dict.values(): self.helper(list(value)) # self.helper(A) return self.results
4 514. 自由之路 https://leetcode-cn.com/problems/freedom-trail/
考点:
1、使用常规的 顺时针,逆时针的深度搜索,会超时
class Solution: def findRotateSteps(self, ring: str, key: str) -> int: # 1至100之间,值不大,尝试使用深度搜索 ring_len = len(ring) key_len = len(key) result = set() result.add(float('inf')) def helper(ikey, cur_pos, cur_step): if not ikey: result.add(cur_step) return if cur_step > min(result): return if ring[cur_pos] == ikey[0]: helper(ikey[1:], cur_pos, cur_step) return # 顺时针 for i in range(1, ring_len): if ikey[0] == ring[(cur_pos + i) % ring_len]: helper(ikey[1:], (cur_pos + i) % ring_len, cur_step + i) break # 逆时针 for i in range(1, ring_len): if ikey[0] == ring[cur_pos - i]: helper(ikey[1:], (cur_pos - i + ring_len) % ring_len, cur_step + i) break helper(key, 0, 0) return min(result) + key_len
1、首先是一个最大值、最小值问题,然后根据前一个值,得到后一个值的最优解,可以使用动态规划
class Solution: def findRotateSteps(self, ring: str, key: str) -> int: ring_len = len(ring) key_len = len(key) grid = [[float('inf')] * ring_len for _ in range(key_len)] # 各元素的位置 pos = collections.defaultdict(list) for i in range(ring_len): pos[ring[i]].append(i) # print(pos) def min_distance(x, y): if x > y: x, y = y, x return min(y-x, ring_len-(y-x)) # 设置初始位置 for index in pos[key[0]]: grid[0][index] = min_distance(0, index) for i in range(1, len(key)): for j in pos[key[i]]: for k in pos[key[i-1]]: # print(grid) grid[i][j] = min(grid[i][j], min_distance(k, j) + grid[i-1][k]) return min(grid[-1]) + len(key)