Array
27. Remove Element #Array #TwoPointers
题目考点
-
in-place with O(1) extra memory
-
The order of elements can be changed. It doesn't matter what you leave beyond the new length.
解题思路
- O(1) 说明算法不会涉及到排序以及暴力遍历,是用swap or 几个temp + replace,此题中有赘余元素,故用replace就好
- 说明最后返回的不要求改变array,只是把赘余的element换到后面去,返回前面的有效长度,所以需要两个位置参数
- 对于array检查为空和只有一个元素的情况
- 注意out of index的问题
代码
def removeElement(self, nums: List[int], val: int) -> int:
l = 0
for i in range(len(nums)):
if nums[i] != val:
nums[i],nums[l],l = nums[l],nums[i],l+1
return l
判断语句处可从swap改为replace,增加效率
if nums[i] != val:
nums[l] = nums[i]
l += 1
加一句判空,如果题目不要求返回任何值,直接写return
if not nums:
return 0
总结
- 循环不变量l代表了有效数组最后一项的后一项的索引,同时也代表了返回的有效数组的长度,取值范围为0到l
- 对于空的list可以直接不进入循环,对于这种不进入后面所有语句的特殊情况,直接在开头返回
26. Remove Duplicates from Sorted Array #Array #TwoPointers
题目考点
- Given a sorted array nums
- in-place with O(1) extra memory
解题思路
- swap or replace in-place with O(1) problem
- 这道题就要考虑空array
- 与1题的区别是要与前一项比较
代码
def removeDuplicates(self, A):
if not A:
return 0
l = 0
for i in range(1, len(A)):
if A[i] != A[l]:
A[l+1] = A[i]
l += 1
return l + 1
循环从1开始是因为要从第一项跟l,即有效数组的最后一项比较,相当于check i - 1项
总结
- 循环不变量l代表了有效数组最后一项的索引,所以最后要返回l+1
- 从进循环方面:要求数组有二项,所以要判空和判1;从题目角度出发,len为0和1的情况就直接返回就好了
80. Remove Duplicates from Sorted Array2 #Array #TwoPointers
题目考点
- modifying the input array in-place with O(1) extra memory
- Given a sorted array nums
解题思路
- 需要check是不是在2次以下,方法1:需要一个count,且每一次到新的数都要置为0;方法2,check i - 2 项
- 注意这里要从0开始,因为count会被开头的项影响
- 一些不用跑循环的特殊情况(0/1/2),在开头就返回避免不必要的运行
代码
解法1
def removeDuplicates(self, nums: List[int]) -> int:
if len(nums) < 3:
return len(nums)
l = 0
count = 0
for cur in range(1, len(nums)):
if nums[cur] != nums[l] :
count = 0
nums[l + 1] = nums[cur]
l += 1
else:
count += 1
if count < 2:
nums[l + 1] = nums[cur]
l += 1
return l + 1
- 逻辑清晰,每次if只进去一次,但看起来不太工整、有重复语句
def removeDuplicates(self, nums: List[int]) -> int:
if len(nums) <= 2:
return len(nums)
l = 0
count = 0
for i in range(1,len(nums)):
if nums[l] != nums[i] :
count = 0
if nums[l] == nums[i] :
count += 1
if (nums[l] != nums[i]) or (nums[l] == nums[i] and count == 1):
nums[l + 1] = nums[i]
l += 1
return l + 1
解法2
- 分步的逻辑清楚,写法工整、没有重复语句,但存在进两个if的情况且if判断较长
- 判断条件尽量不要用闭区间
def removeDuplicates(self, nums: List[int]) -> int:
i = 0
for n in nums:
if i < 2 or n > nums[i-2]:
nums[i] = n
i += 1
return i
总结
- 方法1的循环不变量l代表了有效数组最后一项的索引,故返回l+1;循环不变量count代表了复制的数量
- 设定了参数后,要考虑每个参数该怎么推进。代表的意义、取值范围
- 方法1中因为同样的原因要判空、1
- 方法2是思考了题目的本质(?)后,循环不变量为i,代表有效数组的最后一项的后一项
189. Rotate Array #Array
题目考点
- in-place with O(1) extra memory
解题思路
- swap or replace in-place with O(1) problem
- 很明显这道题所有的元素都是有效的,一定是swap
- swap分一块的(次序不影响)以及单个的,一块的会比单个的多用O(k-1)
- 想象成齿轮的话,并没有类似的数据结构,但可以用同样的array拼接成“齿轮”
代码
解法1 O(n) + O(k) 整块swap
def rotate(self, nums: List[int], k: int) -> None:
l = len(nums)
k = k % l
temp = nums[l - k : l] #extra space
for i in range(len(nums)-1,k-1,-1):
nums[i] = nums[i-k]
for j in range(k):
nums[j] = temp[j]
解法2 O(n) + O(k) 拼接
def rotate(self, nums: List[int], k: int) -> None:
l = len(nums)
k = k % l
nums[:] = nums[-k:] + nums[:-k]
- nums[:]代表对整个list的复制,注意这里如果用“nums = ”是无法拼接的
- 1.在对可变对象进行赋值操作时,得到的只是该对象的引用;2.在对不可变对象进行赋值操作时,将会在内存中复制一份拷副本;3.字典、列表类型的对象为可变对象,整型、字符串、元组等类型的对象为不可变对象。对于可变对象
解法3 O(n) + O(1)单个swap
def rotate(self, nums: List[int], k: int) -> None:
count = 0
l = len(nums)
k %= l
if k == 0:
return
for i in range(k): #一共跑k轮
if count >= l: #count代表被替换过的值的数量
break
index = i #每一轮的初始位置,即要挪动的数
t_last = nums[i] #t_last储存上一个被替换的值
while (index + k) % l != i: #如果跑回了初始位置,即进入死循环,则进入下一轮
t_cur = nums[(index + k) % l] #t_cur储存当前被替换的值
nums[(index + k) % l] = t_last
index = (index + k) % l
t_last = t_cur
count += 1
#替换初始位置
nums[i] = t_last
count += 1
- 循环不变量inx代表的是要挪动的数
- 怎么去判断死循环?即回到初始位置
- 死循环之后怎么办?把初始位置的下一个当做新的初始位置,因为一轮循环后出现死循环,那么初始位置后的k-1个元素一定没有被跑过
- 怎么跳出循环(即交换结束)?给一个count值记录被交换数的数量,这里不用具体到每一个元素有没有被交换
总结
- 卡在了怎么确定死循环很久,因为死循环的位置总是变化的,没有考虑到最多会跑k轮。其实如果会死循环,那么肯定不可能一轮跑完,肯定就会是跑多轮
- 题目一定要思考清楚本质!(大概是数学推论的感觉?直接做肯定是麻烦的,要运用reduction!
41. First Missing Positive #Array
题目考点
- O(n), constant extra space
解题思路
- 暴力解法,对于1到数组长度的数去count,如果是0即输出。这方法很快,因为长度给的短,但是是O(n2)
- O(n)能想到双指针、指针碰撞、DP、In-place,这道题是in-place。把数字放进对应的索引,返回第一个是0的索引
代码
def firstMissingPositive(self, nums: List[int]) -> int:
if not nums:
return 1
l = len(nums)
#put elements in corresponding position
i = 0
while i < l:
if nums[i] < 1 or nums[i] > l: #不在范围内的置0,继续
nums[i] = 0
i += 1
elif nums[i] == i + 1: #在范围内且在自己位置上的,继续
i += 1
elif nums[nums[i] - 1] != nums[i]: #放到该放的位置上
nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]
#nums[i], nums[nums[i] - 1] = nums[nums[i] - 1], nums[i]
else: #对于重复数字,置0
nums[i] = 0
i += 1
#find the first zero element
for inx in range(l):
if nums[inx] == 0:
break
if inx == l - 1 and nums[inx] != 0: #检查最后一项是不是0,如果不是,返回+1
inx += 1
return inx + 1
- 大于数组长度的数字直接不考虑,因为最大的第一缺失正值就是数组的长度+1
- 循环不变量是inx,代表了当前有inx + 1这个数
- python自带的swap语句###nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]###可以运行,但###nums[i], nums[nums[i] - 1] = nums[nums[i] - 1], nums[i]###会报错。因为nums[nums[i] - 1]引用了nums[i]这个值,这个时候nums[i]已经指向了新的值
- 最后找数组中第一个0,注意最后一个数是0和最后一个数不是0都会输出l - 1,所以要多判断一次nums[l-1]的值
- 分类一定要考虑完全啊!所有出现的可能性。这道题做的时候忽略了重复数字的出现。
总结
- 带有swap或者其他指针变化的地方一定要注意。比如之前的深复制浅复制。
- 循环不变量的结束部分要特别注意!(即l - 1的地方
299. Bulls and Cows #HashTable
题目考点
- 一一对应(match)的题就是字典咯
解题思路
- 这里考虑的只是数量,所以不用落实到每一个元素,只要用count或者defaultdict += 1这样的东西来代表就好(无序)。
- 相反,如果要考虑每一个元素,不批次处理,就会发生跟顺序有关的问题,比如"1123"和"0111“。这道题以前一个字符串为基准,那么如果出现两个字符串中某个数字的数量不一样,就无法一一对应,就会出错。(cow会输出2而不是1)因此如果要做一一对应的,就要给一个flag,记录每一个元素是否已经配对。但其实这是没必要的,不用去考虑到这种细节。
代码
def getHint(self, secret: str, guess: str) -> str:
bulls = cows = 0
d = collections.defaultdict(int) #字典里装的是未对应的元素以及其数量
for i, c in enumerate(secret):
if c == guess[i]:
bulls += 1
else:
d[c] += 1
for i, c in enumerate(guess):
if c != secret[i] and d[c] > 0:
cows += 1
d[c] -= 1
return str(bulls) + "A" + str(cows) + "B"
总结
- 看到题目的本质很重要。做这道题的时候老去死磕一一对应,其实是没必要的。本质上我们只需要计数就好。
134. Gas Station #Greedy
题目考点
- 求能否从某一个inx出发使得数组的累和一直大于0
- 贪心算法
解题思路
- 首先要求环绕一圈,所以借鉴189的思路,拼接
代码
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
tmp = [x - y for x, y in zip(gas, cost)]
cur = 0
ans = 0
for i, val in enumerate(tmp + tmp):
cur += val
if cur < 0: #如果跑不动了,重新设置起点
ans = i + 1
cur = 0
if ans >= len(gas): #跑到头了
return -1
return ans
- zip和enumerate很好用呀
总结
- 需要置flag的一般都是错误算法
- 非常明显的贪心,不用在意过去
274. H-Index #HashTable #Sort
题目考点
- 找h, 大于等于h的有h个,小于等于的有h个。注意如果是闭区间的范围,一定要考虑重复的元素
解题思路
- 1,桶排 -> 二分查找
- ***2,看透本质
- 3,hashtable
代码
解法1
def hIndex(self, citations: List[int]) -> int:
if not citations:
return 0
#bucket sort
l = max(citations) + 1
SortList = [0 for item in range(l)]
for i in range(len(citations)):
SortList[citations[i]] += 1
#binary search
left = 0
right = l - 1
while left <= right:
mid = (left + right) // 2
temp = sum(SortList[mid + 1:])
#确定左右移动的范围,要计算inx代表的数字本身的个数
if mid - temp >= 0 and mid - temp <= SortList[mid]:
return mid
elif mid < temp:
left = mid + 1
else:
right = mid - 1
return 0
- 因为桶排序会把相同的元素弄成一块考虑,但这道题是必须考虑重复元素的,所以要多加一个判断
解法2
def hIndex(self, citations: List[int]) -> int:
citations.sort(reverse=True)
for index, value in enumerate(citations):
#如果inx + 1 <= value,代表到inx之前,所有元素都大于当前长度,所以返回inx,且可以推进
#到不能推进的时候就返回前一个的长度,即inx
if index + 1 > value:
return index
return len(citations)
- 题目的本质!循环不变量index代表了返回的h值。h值的取值范围是0到l(如果数组里所有的数都大于数组长度,那么能反对的最大值就是数组长度!
return sum(i < j for i, j in enumerate(sorted(citations, reverse=True)))
- 帅气的一行代码
- 可以推进的话就sum+=1
解法3
def hIndex(self, citations: List[int]) -> int:
l = len(citations)
papers = [0] * (l + 1)
# counting papers for each citation number
for c in citations:
papers[l if l < c else c] += 1
# finding the h-index
k = l
s = papers[l]
while k > s:
k -= 1
s += papers[k]
return k
- 有点像1和2的结合体,看透了本质,但没有用内置的sort而是用了hashtable
- 没有像方法1一样去判断重复元素是因为这里没有用二分查找
总结
- 看透本质真的很重要啊
275. H-Index II #BinarySearch
题目考点
- 已经给了顺序,找符合要求的点,这不是天然的binary search吗
解题思路
- 1,跟274一样的办法,只不过这里是正序,就要倒着来
- 2,二分查找
代码
解法1
def hIndex(self, citations: List[int]) -> int:
l = len(citations)
for i in range(l - 1, -1, -1):
if citations[i] < l - i: #l - i是有效数组的长度
return l - i - 1
return l
- 倒着来,循环不变量变成l - i,意为在这个长度里内的所有值都大于或等于这个长度,就可以继续推进。 取值范围为0 - l,但循环跑完只能返回l - 1,所以要在最后补上l的值
解法2
def hIndex(self, citations: List[int]) -> int:
if not citations:
return 0
l = 0
r = len(citations) - 1
while r < len(citations):
if l == r:
#防止全都不可以但r停在了最后的情况
if citations[r] < len(citations) - r:
return 0
return len(citations) - r
mid = (l + r) // 2
if citations[mid] < len(citations) - mid: #如果不可以,往右边挪一个
l = mid + 1
else: #如果可以,也要把mid算进去
r = mid
- 二分查找,考虑左移和右移的条件,以及停止条件
- 这里判断停止条件会有一个特殊情况,要单独判断
总结
- 想好循环不变量、推进条件、停止条件之后,分别代入普通的情况和特殊的情况验证。
217. Contains Duplicate #Array #HashTable
题目考点
- 很简单的题呢
解题思路
- 1,set
- 2,用字典
- 3,排序后依次check
代码
解法1
return len(nums) != len(set(nums))
- 与重复数字相关的就想到set啦,不过这个占用空间较高
解法2
def containsDuplicate(self, nums: List[int]) -> bool:
check = {}
for x in nums:
if x in check:
return True
else:
check[x] = 1
return False
- 也可以字典+set,不过就画蛇添足了
解法3
def containsDuplicate(self, nums: List[int]) -> bool:
l = len(nums)
if l <= 1:
return False
nums.sort()
for i in range(l-1):
if nums[i] == nums[i+1]:
return True
return False
- 空间占据最少的,加了一个判空和1
总结
- 字典和set同时用的话一般是比较难的题哦
55. Jump Game #Array #Greedy
题目考点
- 典型的贪心哦
解题思路
- 只用记录一个最值就能不用看所有过去的元素 = 贪心
代码
def canJump(self, nums: List[int]) -> bool:
if not nums:
return False
l = len(nums)
maxjump = 0
for i in range(l):
if maxjump < i: #当前i都跳不到
return False
maxjump = max(maxjump, nums[i] + i) #用当前能跳到的来更新maxjump
return maxjump >= l - 1
45. Jump Game II #Array #Greedy
题目考点
- 进阶版55
解题思路
- 1,倒着来,从l - 1到0,对于每个元素,取它所能到达的地方的最小step来更新这个元素的最小step;但这样的时间复杂度是O(kn),太大了
- 2,正向greedy
代码
解法1
def jump(self, nums: List[int]) -> int:
if not nums:
return 0
l = len(nums) - 1
dict = [0] * (l + 1)
dict[l] = 0
for i in range(l - 1, -1, -1):
#find min within distance
if nums[i] == 0:
dict[i] = float('inf')
continue
jump = min(dict[i + 1 : min(l, i + nums[i]) + 1]) #find 所能跳过去的最小Step
#add to dict
dict[i] = jump + 1
return dict[0]
- 这里的思路在于怎么跳过去,所以从离终点最近的能跳过去的点开始,其实更像动归的解法?然而动归总是最慢的
解法2
def jump(self, nums: List[int]) -> int:
step = 0 #record steps
lastpos = 0 #record max distance for given step
maxpos = 0 #record maxjump for i
for i in range(len(nums)):
if i > lastpos:
lastpos = maxpos
step += 1
maxpos = max(maxpos, nums[i] + i)
return step
- 之前没有办法改进解法1的原因是对于每个元素,都必须考虑它能跳的过去的地方的最小值,这是一个变化的东西,所以一定会是O(kn);而没有办法正着循环是因为,如果跳了每一个当前点的最大值,最后可能不是最优解。
- 更宏观的解法2没有具体到考虑怎么跳过去,而是不断更新在每一步step能跳到的最远。不拘泥于具体是哪个点最min,也没有让我们求不是吗
总结
- 要更宏观一些,不要从很细的东西考虑,毕竟要求求的是最值啊!
121. Best Time to Buy and Sell Stock #Array #DynamicProgramming
题目考点
- 只允许一次交易的买股票,即求数组内(带顺序)的最大差
- 最简单的动归了,动归的点在于”记住“之前最小的值
代码
def maxProfit(self, prices: List[int]) -> int:
low = float('inf')
differ = 0
for i in range(len(prices)):
low = min(low, prices[i])
differ = max(differ, prices[i] - low)
return differ
122. Best Time to Buy and Sell Stock II #Array #Greedy
题目考点
- greedy是直接求max(不用记住index之前的元素),动归是在记住东西的基础上求max
- 求无限次数下数组内(带顺序)的最大差,那不是只要增长就加起来就完事了吗
代码
def maxProfit(self, prices: List[int]) -> int:
profit = 0
for i in range(1, len(prices)):
if prices[i] > prices[i-1]:
profit += prices[i] - prices[i-1]
return profit
123. Best Time to Buy and Sell Stock III #Array #DynamicProgramming
为什么宏观的粗糙解法可以得到正确的结果呢
题目考点 (188的特殊情况)
- at most two transactions
- You may not engage in multiple transactions at the same time
- O(n)
解题思路
- 1,给了一个上限k、有次序要求-->动态规划。but这道题是2次上限,考虑用两次动归解决,两次的121
- 2,宏观解法
代码
解法1
def maxProfit(self, prices: List[int]) -> int:
if not prices:
return 0
l = len(prices)
list1 = [0 for i in range(l)]
list2 = [0 for i in range(l)]
#before i, max profit
differ = 0
low = prices[0]
for i in range(l):
differ = max(differ, prices[i] - low)
low = min(low, prices[i])
list1[i] = differ
#after i, max profit
differ = 0
high = prices[l - 1]
for j in range(l - 1, -1, -1):
differ = max(differ, high - prices[j])
high = max(high, prices[j])
list2[j] = differ
#total max
profit = 0
for p in range(l):
profit = max(profit, list1[p] + list2[p])
return profit
解法2
def maxProfit(self, prices: List[int]) -> int:
buy2 = buy1 = float('-inf')
sell1 = sell2 = 0
for price in prices:
buy1 = max(buy1, -price) #first buy
sell1 = max(sell1, buy1 + price) #first sell
buy2 = max(buy2, sell1 - price) #second buy
sell2 = max(sell2, buy2 + price) #second sell
return sell2
- 道理我都懂,但我不明白为什么这样粗糙的思路反而是正确且最快的呢。。很迷惑,思考题
188. Best Time to Buy and Sell Stock IV #DP
题目考点
- Design an algorithm to find the maximum profit. You may complete at most k transactions. 123的一般情况,标准dp
解题思路
- 1,分为当天有交易和没有交易,在有交易的情况下分为当天交易能不能与上一次合并
- 2,宏观解法,对于所有股价,更新每一次交易hold它和release它的值,当然最后一次交易肯定是release
代码
解法1
def maxProfit(self, k: int, prices: List[int]) -> int:
l = len(prices)
#consider special case
if l < 2:
return 0
if k > l / 2:
#return self.maxProfit2(prices)
return sum(i - j for i,j in zip(prices[1:], prices[:-1]) if i - j > 0)
#dp
localmax = [[0] * (k+1) for _ in range(l)]
globalmax = [[0] * (k+1) for _ in range(l)]
for i in range(1, l):
diff = prices[i] - prices[i-1]
for x in range(1, k+1):
localmax[i][x] = max(globalmax[i-1][x-1], localmax[i-1][x] + diff)
globalmax[i][x] = max(globalmax[i-1][x], localmax[i][x])
return globalmax[l-1][k]
#caculate maxprofit without constrains
'''
def maxProfit2(self, prices: List[int]) -> int:
l = len(prices)
profit = 0
for i in range(1, l):
diff = prices[i] - prices[i-1]
if diff > 0:
profit += diff
return profit
'''
- 首先考虑special case,在k >= l //2的时候,相当于无限次交易,即122题 。这里有两种写法,第一种是普通的函数,第二种是更为pythonic的写法,究极复合帅气一行代码
- dp的部分,local代表在当前天有交易,global代表在当前天无交易
- 着眼于每天每次交易的话,就会出现两个二维的数组,占用空间太高了
解法2
def maxProfit(self, k: int, prices: List[int]) -> int:
if k >= len(prices) // 2:
return sum(i - j for i, j in zip(prices[1:], prices[:-1]) if i - j > 0)
hold = [float('-inf')] * (k + 1)
#dp
release = [0] * (k + 1)
for p in prices:
for i in range(1, k + 1):
release[i] = max(release[i], hold[i] + p)
hold[i] = max(hold[i], release[i - 1] - p)
'''
if hold[i] + p > release[i]:
release[i] = hold[i] + p
if i and release[i - 1] - p > hold[i]:
hold[i] = release[i - 1] - p
'''
return release[k]
- special case的处理方式相同
- dp的部分,release[i]代表在第i次交易,卖掉了这个p;hold[i]代表在第i次交易,买入了这个p
- 没有想出来的原因:在想如果当天是卖掉,那么怎么知道是哪天买的呢?答案:不需要知道,+ p 就完事了
- 没有具体考虑每天怎么买怎么卖,而是更宏观的直接看。对于每个元素只有两种情况。
- 改进1:如果不用max形式而是简单地用if判断能快(从90->60)
- 改进2:可以用dp[i][0] & dp[i][1]来代替两个list,空间仿佛会小一点
总结
- 宏观的思路感觉依旧不清晰。现在的感悟:不是对每个点找递推而是对限制条件的推进找递推(比如这道题的k);具体到每个元素来说,更多的是给它们严格的分类,或者说找所有可能的状态,比如这里的release&hold
309. Best Time to Buy and Sell Stock with Cooldown
题目考点
- 123加了一个cooldown的状态
解题思路
- 有限状态机
- DP
代码
解法1
def maxProfit(self, prices: List[int]) -> int:
if not prices:
return 0
l = len(prices)
s0 = [0] * l
s1 = [0] * l
s2 = [0] * l
s1[0] = -prices[0]
for i in range(1, l):
s0[i] = max(s0[i-1], s2[i-1])
s1[i] = max(s0[i-1] - prices[i], s1[i-1])
s2[i] = s1[i-1] + prices[i]
return max(s0[l-1], s2[l-1])
- s0代表sell后的rest或者rest后的rest;s1代表rest后的buy或者buy后的rest;s2代表rest后的sell
解法2
def maxProfit(self, prices: List[int]) -> int:
if len(prices) < 2: return 0
hold = - prices[0]
sold = 0
rest = 0
for price in prices:
sold = max(sold, hold + price)
hold = max(hold, rest - price)
rest = max(rest, prev_sold)
return max(sold, rest)
总结
状态转移方程法,比较basic但还是要落实到题目本质
11. Container With Most Water #Array #Two pointers
解题思路
- 双指针
代码
def maxArea(self, height: List[int]) -> int:
l = len(height)
left = 0
right = l-1
contain = 0
while left < right:
contain = max(contain, min(height[left], height[right]) * (right - left))
if height[left] < height[right]:
left += 1
else:
right -= 1
return contain
总结
- 循环不变量,所以停止条件是left = right
- 双指针能推进的原因是每一步都可以舍弃一部分,比如1-7变成1-6,是有理由地舍弃了0-这一堆
42. Trapping Rain Water #Array #Two pointers #Stack
解题思路
- 暴力动归?其实是储存了一点东西,也不算动归,感觉更像贪心
- ***栈的应用
- ***双指针
代码
解法1
def trap(self, height: List[int]) -> int:
l = len(height)
if l < 3:
return 0
maxleft = [0] * l
maxright = [0] * l
#find left
maxleft[0] = height[0]
for i in range(1, l):
maxleft[i] = max(maxleft[i-1], height[i])
#find right
maxright[l-1] = height[l-1]
for j in range(l-2, -1, -1):
maxright[j] = max(maxright[j+1], height[j])
water = 0
for p in range(l):
water += min(maxleft[p], maxright[p]) - height[p]
return water
- 分别储存左max和右max
- 在寻找左右max时出现了问题,因为太拘泥于具体的趋势,其实我要的就是一个max而已啊,不断更新就完了
解法2
总结
334. Increasing Triplet Subsequence
题目考点
解题思路
代码
总结
128. Longest Consecutive Sequence
题目考点
解题思路
代码
总结
164. Maximum Gap
题目考点
解题思路
代码
总结
287. Find the Duplicate Number
题目考点
解题思路
代码
总结
4. Median of Two Sorted Arrays
289. Game of Life
57. Insert Interval
56. Merge Intervals
352. Data Stream as Disjoint Intervals