2021-12-16 每日打卡:难题精刷
写在前面
“这些事儿在熟练之后,也许就像喝口水一样平淡,但却能给初学者带来巨大的快乐,我一直觉得,能否始终保持如初学者般的热情、专注,决定了在做某件事时能走多远,能做多好。” 该系列文章由python编写,所刷题目共三个来源:之前没做出来的 ;Leetcode中等,困难难度题目; 周赛题目;某个专题的经典题目,所有代码已AC。每日1-3道,随缘剖析,希望风雨无阻,作为勉励自己坚持刷题的记录。
41. 缺失的第一个正数
很好想到的一个思路是:我们可以将数组所有的数放入哈希表,随后从 11 开始依次枚举正整数,并判断其是否在哈希表中。
这是因为哈希表是一个可以支持快速查找的数据结构:
给定一个元素,我们可以在 O(1) 的时间查找该元素是否在哈希表中。
因此,我们可以考虑将给定的数组设计成哈希表的「替代产品」。
而充分利用一下题目条件,对于长度为N的数组,最小整数的范围只能在1~N+1中:
我们对数组进行遍历,对于数 x,如果它在 [1, N] 的范围内
那么就将数组中的第 x-1个位置(注意:数组下标从 0 开始)打上「标记」。
在遍历结束之后,如果所有的位置都被打上了标记,
那么答案是 N+1,否则答案是最小的没有打上标记的位置加 1。
但是!考虑我们想要使用原有数组的位置,就难免覆盖了后面需要的值,除非,我们制定某种规则,比如,使用负号,统一加上一个数固定的数这类。
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
n = len(nums)
for i in range(n):
if nums[i] <= 0:
nums[i] = n + 1
for i in range(n):
num = abs(nums[i])
if num <= n:
nums[num - 1] = -abs(nums[num - 1])
for i in range(n):
if nums[i] > 0:
return i + 1
return n + 1
42. 接雨水
- 动态规划:对于下标 i,下雨后水能到达的最大高度等于下标 ii 两边的最大高度的最小值,下标 i 处能接的雨水量等于下标 ii 处的水能到达的最大高度减去 height[i]。
class Solution:
def trap(self, height: List[int]) -> int:
if not height:
return 0
n = len(height)
leftMax = [height[0]] + [0] * (n - 1)
for i in range(1, n):
leftMax[i] = max(leftMax[i - 1], height[i])
rightMax = [0] * (n - 1) + [height[n - 1]]
for i in range(n - 2, -1, -1):
rightMax[i] = max(rightMax[i + 1], height[i])
ans = sum(min(leftMax[i], rightMax[i]) - height[i] for i in range(n))
return ans
- 双指针做法:
class Solution:
def trap(self, height: List[int]) -> int:
ans = 0
left, right = 0, len(height) - 1
leftMax = rightMax = 0
while left < right:
leftMax = max(leftMax, height[left])
rightMax = max(rightMax, height[right])
if height[left] < height[right]:
ans += leftMax - height[left]
left += 1
else:
ans += rightMax - height[right]
right -= 1
return ans
另外,今天还做了两道中等难度的题,小感悟:
- 滑动窗口往往是从两遍遍历演变过来的,用于上一次解答对这一次有帮助
- 对空间有要求,想原地交换,利用输入的数据结构即可!