【周赛总结】第28场双周赛——不重叠的子数组,邮筒投递

2020/06/13 rank 326 ac 3

引言

感觉最近状态都不是特别好,可能下周会给自己放个假,暂时不比赛。

第一题

简单题目
【周赛总结】第28场双周赛——不重叠的子数组,邮筒投递_第1张图片

可以用暴力的方法,也可以采用单调栈的方法作为连续,这里放一下单调栈的方法。

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

对于单调栈的题目,有几点想说的:

  1. 单调栈的题目首先是清楚,维护升序还是降序,对立面是打破平衡需要处理的那种
  2. 单调栈的问题一般都是存储索引的
  3. 对于最后的结果,如果没有发生弹栈如何处理。处理好这部分数值。

第二题矩阵的查询就不写了

找两个和为目标值且不重叠的子数组

【周赛总结】第28场双周赛——不重叠的子数组,邮筒投递_第2张图片

题目的特点在于连续的子区间和,因此可以考虑用前缀和的方法,因为要求最短,每次得到的新的前缀和都去进行更新为最新的(其实因为没有复数,可以不用)。

另外的难点在处理不重复的子区间的问题,这里维护了一个区间,记录了左右的索引,然后从小向大选择,保证不重复。

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



安排邮筒

【周赛总结】第28场双周赛——不重叠的子数组,邮筒投递_第3张图片

其实想到了应该是一道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]

你可能感兴趣的:(周赛总结)