[LeetCode111双周赛&LeetCode359周赛] DP&双指针

参考灵神和闫总的讲解和代码:
https://www.bilibili.com/video/BV1rP411s7Z5
https://space.bilibili.com/206214

7006. 销售利润最大化

https://leetcode.cn/problems/maximize-the-profit-as-the-salesman/

Solution

动态规划 + 哈希表

首先按照 end 的顺序分组,每个组记录所有以 end 为终点的区间。

f[i+1] 表示不超过 i 的房屋的最大盈利。

  • 若编号 i 的房屋不卖,从上一个编号转移过来,f[i + 1] = f[i]
  • 若卖,需要遍历所有以 i 为终点的区间,找出最大的 f[s] + g
  • 取最大即可
class Solution:
    def maximizeTheProfit(self, n: int, offers: List[List[int]]) -> int:
        groups = [[] for _ in range(n)]
        for s, e, g in offers:
            groups[e].append((s, g))
        # f[i+1] 表示编号不超过 i 的房屋的最大盈利
        f = [0] * (n + 1)
        for end, group in enumerate(groups):
            # 不选
            f[end + 1] = f[end]
            for s, g in group:
                # 选
                f[end + 1] = max(f[end + 1], f[s] + g)
        return f[n]

6467. 找出最长等值子数组

https://leetcode.cn/problems/find-the-longest-equal-subarray/

Solution

同相双指针

[LeetCode111双周赛&LeetCode359周赛] DP&双指针_第1张图片

class Solution:
    def longestEqualSubarray(self, nums: List[int], k: int) -> int:
        pos = [[] for _ in range(len(nums) + 1)]
        for i, x in enumerate(nums):
            pos[x].append(i)
        ans = 0
        for ps in pos:
            left = 0
            for right, p in enumerate(ps):
                while p - ps[left] - (right - left) > k:
                    left += 1
                ans = max(ans, right - left + 1)
        return ans

Solution

暴力方法

class Solution:
    def minimumOperations(self, nums: List[int]) -> int:
        # 暴力方法
        res = n = len(nums)
        for i in range(n + 1):
            for j in range(n - i + 1):
                cnt = 0
                for k in range(n):
                    t = -1
                    if k <= i - 1:
                        t = 1
                    elif k <= i + j - 1:
                        t = 2
                    else:
                        t = 3
                    # 有多少不同
                    if t != nums[k]:
                        cnt += 1
                res = min(res, cnt)
        
        return res

最长子序列

@https://leetcode.cn/u/xiongxyowo/
最长递增子序列。为了在最少操作次数内使得数组有序,我们只需要对不在最长递增子序列中的元素进行修改,使其满足递增要求即可。也就是求原数组长度减去最长递增子序列长度。
例如,[1,3,2,1,3,3] 的最长递增子序列为 [1,-,2,-,3,3],我们只需要修改 [-,3,-,1,-,-] 即可。代码如下:

class Solution:
    def minimumOperations(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [1] * n
        for i in range(1, n):
            for j in range(0, i):
                if nums[i] >= nums[j]:
                    dp[i] = max(dp[i], dp[j] + 1)
        return n - max(dp)

DP

最少修改多少个数字可以使数组非递减。定义 a, b, c 分别表示以 1, 2, 3 结尾的前缀数组需要修改的最小次数。

class Solution:
    def minimumOperations(self, nums: List[int]) -> int:
        a, b, c = 0, 0, 0
        for x in nums:
            aa, bb, cc = a, b, c
            if x == 1:
                a = aa # 因为本身就是 1,所以不用修改
                b = min(aa, bb) + 1
                c = min(aa, bb, cc) + 1
            elif x == 2:
                a = aa + 1
                b = min(aa, bb)
                c = min(aa, bb, cc) + 1
            else:
                a = aa + 1
                b = min(aa, bb) + 1
                c = min(aa, bb, cc)
        return min(a, b, c)

你可能感兴趣的:(算法,leetcode,算法)