返回

LeetCode周赛294:硬核压轴题的手速场

闲谈

各位程序员小伙伴们,大家好!我是梁唐,今天我们一起复盘一下刚刚结束的 LeetCode 周赛 294。本场比赛由普渡机器人赞助,前 300 名完赛选手将获得内推机会,大家有没有把握住呢?

这场比赛的题目难度整体适中,尤其是最后一题「」,堪称手速场。很多同学在赛后都直呼「手速不够用」!但大家也不必灰心,接下来我会详细解析这道题,带大家一起领略算法竞赛的魅力。

本题给定一个整数数组 nums 和一个正整数 k。要求我们删除至多 k 个元素后,使得剩余元素的全排列字典序最小。我们的目标是输出删除元素后的数组的全排列列表。

乍一看,这道题似乎需要暴力枚举所有可能的删除方案,然后计算每个方案对应的剩余元素排列的字典序,最后输出字典序最小的方案。然而,这种朴素的解法时间复杂度太高,无法通过本题的时限要求。

为了解决这个问题,我们可以采用状态压缩动态规划的方法。具体步骤如下:

1. 定义状态 dp[i][j][k],表示考虑前 i 个元素,已经删除 j 个元素,且剩余元素字典序最小时,剩余元素的排列情况。
2. 初始化 dp[0][0][0] = {},表示空数组的排列为空集。
3. 对于每个元素 nums[i],依次枚举是否删除该元素:
    - 如果删除,则有 dp[i][j][k] = dp[i-1][j-1][k]。
    - 如果不删除,则有 dp[i][j][k] = min(dp[i][j][k], dp[i-1][j][k] + [nums[i]])。其中,min 表示取字典序最小的排列。
4. 最终答案为 dp[n][k][k]

通过这种方法,我们可以将时间复杂度优化到 O(n * 2^n * k),其中 n 为数组长度。

```python
def get_permutations(nums, k):
    n = len(nums)
    dp = [[[set() for _ in range(k+1)] for _ in range(k+1)] for _ in range(n+1)]

    dp[0][0][0] = set()

    for i in range(1, n+1):
        for j in range(k+1):
            for l in range(k+1):
                dp[i][j][l] = dp[i-1][j][l]
                if l > 0:
                    dp[i][j][l] |= dp[i-1][j-1][l] + set([nums[i-1]])

    return list(dp[n][k][k])

以上就是 LeetCode 周赛 294 硬核压轴题「删除满足条件元素后数组的全排列」的详细解析。希望通过这篇文章,大家能够对动态规划的思想和技巧有更深入的理解。

最后,再次恭喜获得内推机会的同学,希望大家再接再厉,在算法竞赛的道路上不断进步!