Leetcode 3049. Earliest Second to Mark Indices II

  • [Leetcode 3049. Earliest Second to Mark Indices II](#Leetcode 3049. Earliest Second to Mark Indices II)
    • [1. 解题思路](#1. 解题思路)
    • [2. 代码实现](#2. 代码实现)
    • [3. 算法优化](#3. 算法优化)

1. 解题思路

这道题我看貌似难度报表,比赛的时候貌似只有36个人搞定了这道题目,然后最快的人耗时也花了40min以上,就很离谱,和平时基本15分钟就能有大佬全部做出来4道题的情况完全不懂,就很吓人。

所以基本上我对这道题也算是一个半放弃的状态,不过后来还是看了一下,然后发现其实也不是完全无法上手,本质上还是求一个处理的最优解,且显然这个操作依然是单调的,即从某一个位置开始,后续所有的操作序列都可以使得所有的位置都被mark上。

因此,最开始我的思路也是二分法来求任意一个位置作为操作序列的结束点时能否判断其是否可以使得所有的位置都被mark上,然后就和上一题一样,这里就变成了一个贪婪算法,要最优的分配点数使得所有的值都可以先降为0然后再mark上。

但是比较尴尬的是这里我们的贪婪算法并没有完成,因此有以下一个判断无法彻底想明白:

  • 已知任何一次直接归零操作都必须附加一次mark操作进行完成,因此对于任意一个点,我们需要判断是否要等待后续直接操作位然后再多加一轮操作使之mark还是直接使用当前富裕的点数(如果有的话)进行归零然后mark。

因此后续干脆就是直接绕开这个,走了最暴力的动态规划的方法,遍历了所有的可能,即每一个位置到底是走的快速清零还是进行-1或者mark操作,这里,显然如果要进行快速清零那必然是在某个位置在changeIndices当中最早出现的位置上。

但是,直接地实现会出现内存爆炸的情况,因此,我们做了一些不严谨的剪枝,即如果某次快速清零可以省出100以上的富裕,那么必走快速清零,反之考虑是否忽略掉这个快速清零的路线。

需要强调,这个方式是不严谨的,因为如果存在全面富裕了非常多的点数远大于100,而最后来一个可以清空100的操作,那不一定要走快速清零的,因为那样会需要额外多一次操作。

但是对于绝大多数的情况上述结果是对的,在这里也确实可以通过测试样例。

2. 代码实现

给出python代码实现如下:

python 复制代码
class Solution:
    def earliestSecondToMarkIndices(self, nums: List[int], changeIndices: List[int]) -> int:
        n, m = len(nums), len(changeIndices)
        changeIndices = [x-1 for x in changeIndices]
        needed = sum(nums) + n
        first_seen = {}
        for i, x in enumerate(changeIndices):
            if x not in first_seen and nums[x] > 1:
                first_seen[x] = i
        first_seen = {v:k for k, v in first_seen.items()}

        @lru_cache(None)
        def dp(idx, need, extra):
            if need <= 1 and extra <= 1:
                return idx
            elif idx >= m:
                return m
            if idx not in first_seen:
                return dp(idx+1, need-1, max(extra-1, 0))
            i = first_seen[idx]
            if nums[i] >= 100:
                return dp(idx+1, need-nums[i], extra+1)
            else:
                return min(dp(idx+1, need-1, max(extra-1, 0)), dp(idx+1, need-nums[i], extra+1))
            
        ans = dp(0, needed, 0)
        return ans+1 if ans != m else -1

提交代码评测得到:耗时1219ms,占用内存288.9MB。

3. 算法优化

因为前面也反复强调了,上述解法有效,但是剪枝的存在使得上述解法并不严谨,因此,我们在这里摘录一下其他大佬们的解法作为补充,有兴趣的读者可以自行研读学习一下,这里就让我偷个懒了......

python 复制代码
class Solution:
    def earliestSecondToMarkIndices(self, nums: List[int], changeIndices: List[int]) -> int:
        first_idx = [-1] * len(nums)
        for i in range(len(changeIndices)):
            if first_idx[changeIndices[i]-1] == -1:
                first_idx[changeIndices[i]-1] = i

        for i, num in enumerate(nums):
            if num <= 1:
                first_idx[i] = -1

        default_needs = sum(nums) + len(nums)

        def is_possible(k):
            left = 0
            h = []

            pos_count = 0
            flag = False
            for j in range(k, -1, -1):
                if flag:
                    pos_count += 1
                    flag = False
                else:
                    flag = True

                left += 1

                i1 = first_idx[changeIndices[j]-1]
                if i1 == j:
                    heapq.heappush(h, [nums[changeIndices[j]-1] - 1, changeIndices[j]-1])
                if len(h) > pos_count:
                    heapq.heappop(h)

            return default_needs - sum(h1[0] for h1 in h) <= left

            ans = 0
            return ans

        l, r = len(nums)-1, len(changeIndices)-1
        while l < r:
            m = (l + r) // 2
            if is_possible(m):
                r = m
            else:
                l = m + 1
        if l > r or not is_possible(l):
            return -1
        return l+1
相关推荐
_GR41 分钟前
每日OJ题_牛客_牛牛冲钻五_模拟_C++_Java
java·数据结构·c++·算法·动态规划
LluckyYH15 小时前
代码随想录Day 58|拓扑排序、dijkstra算法精讲,题目:软件构建、参加科学大会
算法·深度优先·动态规划·软件构建·图论·dfs
ganjiee00073 天前
力扣(leetcode)每日一题 983 最低票价 |动态规划
算法·leetcode·动态规划
EQUINOX13 天前
思维+贪心,CF 1210B - Marcin and Training Camp
算法·数学建模·动态规划
_GR3 天前
每日OJ题_牛客_JOR26最长回文子串_C++_Java
java·数据结构·c++·算法·动态规划
源代码•宸4 天前
小米2025届软件开发工程师(C/C++/Java)(编程题AK)
c语言·c++·经验分享·算法·动态规划
Jcqsunny4 天前
[dp] 小信走迷宫
算法·前缀和·动态规划·dp
mengsi555 天前
最大正方形 Python题解
开发语言·python·leetcode·前缀和·动态规划·洛谷·acwing
Black—slience5 天前
LeetCode2207解题思路
java·算法·leetcode·动态规划
AnFany6 天前
数据结构编程实践20讲(Python版)—01数组
开发语言·数据结构·python·深度优先·动态规划