题目一:
题目链接: https://leetcode-cn.com/problems/destination-city/
解题思路:
把所有起终点信息,放入到hash表中,key = 起点,val = 终点
然后遍历hash表,如果某个终点在hash表中没有对应的key,说明是最终终点
代码实现:
class Solution:
def destCity(self, paths: List[List[str]]) -> str:
rec = {a : b for a, b in paths}
for key in rec:
dst = rec[key]
if dst not in rec:
return dst
return ''
题目二:
题目链接: https://leetcode-cn.com/problems/check-if-all-1s-are-at-least-length-k-places-away/
解题思路:
双指针,遍历数组的同时,使用一个指针指向上一个1的位置
遍历中间遇到1时,计算与上一个1的距离,并更新上一个1的位置到当前位置
代码实现:
class Solution:
def kLengthApart(self, nums: List[int], k: int) -> bool:
last_pos = -1
for idx, a in enumerate(nums):
print(last_pos, idx)
if a != 1:
continue
elif last_pos == -1:
last_pos = idx
continue
elif idx - last_pos - 1 < k:
return False
last_pos = idx
return True
题目三:
解题思路:
遍历数组的同时,记录当前遍历子串中的最大值、最大值位置、最小值、最小值位置
如果发现最大值 - 最小值 > limit,则使用min(最大值位置, 最小值位置)的下一位重新开始遍历
代码实现:
class Solution:
def longestSubarray(self, nums: List[int], limit: int) -> int:
# 记录的最小值信息
min_info = [nums[0], 0]
# 记录的最大值信息
max_info = [nums[0], 0]
# idx : 遍历指针,从1开始
# longest : 最长子串
# curr_len : 当前子串长度
# 因为是从第二位开始遍历,所以两个长度初始化为1
idx = longest = curr_len = 1
while idx < len(nums):
curr_num = nums[idx]
# 判断当前值与最大、最小值的绝对差,取最大的一个
curr_diff = max(abs(curr_num - min_info[0]), abs(curr_num - max_info[0]))
# 如果最大的绝对差比limit小, 更新信息, 继续遍历
if curr_diff <= limit:
# 更新当前长度+1
curr_len += 1
# 更新最大子串长度
longest = max(longest, curr_len)
# 更新最大、最小值信息
if curr_num <= min_info[0]:
min_info = [curr_num, idx]
if curr_num >= max_info[0]:
max_info = [curr_num, idx]
# 向后移动指针
idx += 1
continue
# 如果当前值不符合要求
# 从最大值、最小值下标中更小一个的下一位重新开始遍历
idx = min(min_info[1], max_info[1]) + 1
# 保护性判断
if idx >= len(nums):
break
# 更新当前长度为1
curr_len = 1
# 更新最大、最小值信息为最大值、最小值下标更小一个的下一位信息
min_info = [nums[idx], idx]
max_info = [nums[idx], idx]
# 向后移动指针
idx += 1
return longest
题目四:
题目链接: https://leetcode-cn.com/problems/find-the-kth-smallest-sum-of-a-matrix-with-sorted-rows/
解题思路:
专门截图了提示,是因为有k <= 200的限制,所以直接暴力,最终是没有超时的
暴力的方法就不解释了,这里只写二分查找
具体逻辑写在代码注释中
代码实现:
class Solution:
def kthSmallest(self, mat: List[List[int]], k: int) -> int:
def dfs(mat, k, max_sum, idx, curr_sum, cnt):
# 计算所有小于max_sum的个数
# 递归退出条件
# 额外注意的是cnt[0] > k这个条件,只要当前小于max_sum的个数已经大于k了,就不需要继续遍历了
# 因为已经知道如何继续下一次遍历查找了
if idx == len(mat) or curr_sum > max_sum or cnt[0] > k:
return
# 因为curr_sum的初始值为原始的left值,所以先递归到最后一层开始,从最后一层的第二个数还是加
dfs(mat, k, max_sum, idx + 1, curr_sum, cnt)
# 遍历当前层数组从第二个数字开始的和,是否小于max_sum
for i in range(1, len(mat[idx])):
# 因为每层数组只能取一个元素,所以更新当前和时,需要减去第一个元素的值
tmp_sum = curr_sum + mat[idx][i] - mat[idx][0]
# 剪枝条件,如果当前和已经大于max_sum,则后续的所有值也大于
# 因为只计算小于的个数, 所以此时退出
if tmp_sum > max_sum:
break
# 更新结果数目
cnt[0] += 1
# 以当前和为基准,继续遍历之后的每一层
dfs(mat, k, max_sum, idx + 1, tmp_sum, cnt)
return
left = right = 0
for idx in range(len(mat)):
# 每一层最小数字相加
left += mat[idx][0]
# 每一层最大数字相加
right += mat[idx][-1]
# 因为遍历过程中,需要更新left的值
# 但是每次dfs遍历时,需要使用最小值进行当前值的计算
# 所以此处记录最小值(详细见dfs中for循环内第一个注释内容)
base = left
while left < right:
mid = (left + right) // 2
cnt = [1]
dfs(mat, k, mid, 0, base, cnt)
if cnt[0] < k:
left = mid + 1
else:
right = mid
return right