2020/06/13 rank 326 ac 3
引言
感觉最近状态都不是特别好,可能下周会给自己放个假,暂时不比赛。
第一题
简单题目
可以用暴力的方法,也可以采用单调栈的方法作为连续,这里放一下单调栈的方法。
class Solution(object):
def finalPrices(self, prices):
# 单调栈的方法,需要考虑不修改的情况,这里直接用ans,另外单调栈一般都是存储索引
stack = []
ans = prices[:]
for i in range(len(prices)):
while stack and prices[i]<=prices[stack[-1]]:
ans[stack[-1]] = prices[stack[-1]]-prices[i]
stack.pop()
stack.append(i)
return ans
对于单调栈的题目,有几点想说的:
- 单调栈的题目首先是清楚,维护升序还是降序,对立面是打破平衡需要处理的那种
- 单调栈的问题一般都是存储索引的
- 对于最后的结果,如果没有发生弹栈如何处理。处理好这部分数值。
第二题矩阵的查询就不写了
找两个和为目标值且不重叠的子数组
题目的特点在于连续的子区间和,因此可以考虑用前缀和的方法,因为要求最短,每次得到的新的前缀和都去进行更新为最新的(其实因为没有复数,可以不用)。
另外的难点在处理不重复的子区间的问题,这里维护了一个区间,记录了左右的索引,然后从小向大选择,保证不重复。
class Solution(object):
def minSumOfLengths(self, arr, target):
## 前缀和++哈希
dic = collections.defaultdict(int)
dic[0] = -1
cur = 0
ans = []
for i in range(len(arr)):
cur += arr[i]
if cur-target in dic:
ans.append([i-dic[cur-target], [dic[cur-target]+1,i]])
dic[cur] = i
if len(ans)<2:
return -1
ans.sort(key = lambda x:x[0])
left = ans[0][1][0]
right = ans[0][1][1]
res = ans[0][0]
for i in range(1,len(ans)):
if ans[i][1][0]>right or ans[i][1][1]<left:
return res+ans[i][0]
return -1
安排邮筒
其实想到了应该是一道dp的问题,但是还是把问题复杂化了。
状态:dp[i][j]
包括索引i
在内的前面的房子,安排j
个邮筒的最短距离
状态转移:我们需要另外维护一个数组,cost[i][j]
表示从i
位置到j
位置的,只安排一个邮筒的情况。这里考虑一个绝对值不等式,这种情况下,邮筒设置在中位数的房子那里最合适。
因此dp[i][j] = min(dp[i][j], dp[p][j-1]+cost[p+1][i]
依次枚举,最后一个邮筒的管辖范围。需要注意的是,当有j
个房子时候,邮筒数量最多j
个即可。
class Solution:
def minDistance(self, houses: List[int], k: int) -> int:
## dp[i][j] 表示到索引i个位置,安排j个邮筒
## cost[i][j] 表示从ii到j,一个邮筒的成本
houses.sort()
n = len(houses)
cost = [[0]*n for _ in range(n)]
for i in range(n):
for j in range(i,n):
mid = (i+j)//2
for p in range(i,j+1):
cost[i][j] += abs(houses[p]-houses[mid])
dp = [[float('inf')]*(k+1) for _ in range(n)]
for i in range(n):
dp[i][1] = cost[0][i]
for i in range(n):
for j in range(2,min(k, i+1)+1):
## 需要注意dp[p-1][j-1] 是在索引p-1位置,也就是前面有p个房子,最多只能p个邮筒,因此从dp[j-2][j-1]
for p in range(j-2,i):
dp[i][j] = min(dp[i][j], dp[p][j-1]+cost[p+1][i])
return dp[n-1][k]