LeetCode 5394.找到和最大的长度为K的子序列

给定整数数组nums和整数k,找出一个长度为k且和最大的子序列。需要先对数组排序,记录每个元素的下标,然后选择前k个最大值,再按原下标顺序排列,以获取最大和子序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

给你一个整数数组 nums 和一个整数 k 。你需要找到 nums 中长度为 k 的 子序列 ,且这个子序列的 和最大 。

请你返回 任意 一个长度为 k 的整数子序列。

子序列 定义为从一个数组里删除一些元素后,不改变剩下元素的顺序得到的数组。

被自己菜到了,周赛的时候想了半天才整出来 最开始往递归dfs的思路走,但实际就是求最大和的不连续子序列,于是只需要先按值排序,并记录下标,之后取出前k个值后再按下标升序排序得到原先的相对位置,即可获得答案。

class Solution {
   
   
    public int[] maxSubsequence(int[] nums, int k) {
   
   
        int len = nums.length;
        int[][] tmp = new int[len]
<think>好的,用户现在想解决LeetCode上关于寻找长度为k且最大子序列的问题。首先,我需要回忆相关的题目解法。根据用户提供的引用,特别是引用[2][5],LeetCode 2099题就是这个问题。用户提到需要算法或解题思路,所以我要先整理已有的信息。 首先,子序列数组不同,子序列不要求连续,但顺序必须保持。题目要求长度为k,且最大。常见的思路可能是先排序然后取最大的k个数,但这样会破坏顺序,导致得到的子序列顺序与原数组不符。比如,如果数组是[3,1,4,2],k=2,排序后最大的两个数是43,但原数组中4在3之后,所以正确的子序列应该是[3,4],但直接排序选最大的两个可能得到[4,3],顺序不对。因此,直接排序不行,需要考虑其他方法。 引用[5]中提到了选择排序的方法,每次选出剩余元素中的最大值,并记录其索引,然后将该位置置为None,避免重复选择。最后根据记录的索引排序,得到正确顺序的子序列。这种方法的时间复杂度是O(nk),当k较小时比较高效。但若k接近n,则可能达到O(n²),不过题目可能数据规模不大,可以接受。 另一种方法是使用堆(优先队列),如引用[2]提到的堆解法。具体来说,可以维护一个大小为k的最大堆,或者使用堆来快速找到最大的k个元素及其索引。不过需要注意保持元素的顺序。可能的步骤是:遍历数组,将元素索引存入堆中,按值从大到小排序。取出前k个元素后,根据索引排序,得到正确顺序的子序列。这种方法的时间复杂度是O(n log n),因为堆的插入操作是O(log n),而最后对k个元素排序是O(k log k)。对于较大的n,这种方法可能更优。 然后,我需要考虑动态规划是否有适用的可能,但根据问题特点,子序列需要保持顺序,并且长度固定为k,最大。动态规划的状态可能设计为dp[i][j],表示前i个元素中长度为j的子序列最大。状态转移方程需要考虑是否选择当前元素。但这样的动态规划时间复杂度是O(nk),可能选择排序方法相当,但实现起来稍微复杂。不过引用中没有提到动态规划解法,可能更推荐堆或选择方法。 现在需要比较这两种方法的优劣。堆方法的时间复杂度更低,尤其是当k较大时。而选择排序方法在k较小时更优,实现简单。根据题目给出的示例代码,引用[5]中的解法就是选择排序的思路,每次选最大的元素,记录索引,最后按索引排序输出。这可能更适合快速实现,尤其是在编程比赛中。 另外,还需要注意重复元素的情况。例如,如果有多个相同的最大值,需要正确选择它们的索引,以保持子序列的顺序。例如数组[5,3,5,2],k=2,应选择第一个5第二个5,子序列是[5,5],但它们的索引分别是02,所以最终输出应为[5,5]。 总结可能的解题步骤: 1. 遍历数组找到最大的k个元素,并记录它们的值原始索引。 2. 根据记录的索引进行排序,确保子序列的顺序与原数组一致。 3. 提取对应的值形成结果子序列。 在实现时,需要注意如何处理元素的选择,确保每次选的是当前剩余元素中的最大值,同时记录索引。引用[5]中的代码通过将已选元素置为None来避免重复选择,这可能有效,但修改原数组是否允许需要考虑题目要求。如果题目不允许修改原数组,可能需要复制数组或使用其他方式标记已选元素。 另外,堆方法如何实现?例如,可以将所有元素索引一起存入堆中,按值从大到小排序。取出前k个元素后,根据索引排序,然后输出对应的值。这样可以避免修改原数组,并且时间复杂度为O(n + k log k),因为堆化需要O(n)时间(如果使用heapq.nlargest),然后对k个元素排序需要O(k log k)。这可能更高效,尤其是当n较大时。 因此,用户的问题需要给出这两种可能的解法,并比较它们的优缺点。同时,引用中的示例代码使用的是选择排序的方法,而引用[2]提到了堆解法,所以需要详细说明这两种方法,并给出代码示例。 另外,需要注意子序列数组的区别,确保解答中明确说明这一点。例如,子序列不需要连续,但顺序必须保持,而子数组是连续的。 最后,根据用户提供的引用,特别是引用[2][5],需要将这两种方法整合到回答中,并正确引用对应的参考资料。</think>### LeetCode 2099. 找到最大长度为 K 的子序列 #### 问题分析 题目要求从整数数组 $nums$ 中选出长度为 $k$ 的子序列,使得其最大,且保持元素的原始顺序[^2]。由于子序列不要求连续,但必须保持顺序,直接排序会破坏索引关系,因此需要结合数值大小索引顺序进行选择。 --- ### 核心解法 #### 1. 选择排序法(贪心思想) **思路**:每次选择当前剩余元素中的最大值,记录其索引,并将该位置标记为已选(例如置为 `None`),重复此过程直到选满 $k$ 个元素。最后根据索引顺序输出结果。 - **时间复杂度**:$O(nk)$,适用于 $k$ 较小的情况。 - **空间复杂度**:$O(1)$(原地修改数组)或 $O(n)$(使用辅助数组)。 ```python def maxSubsequence(nums, k): ans = [] for _ in range(k): max_val, max_idx = -float('inf'), -1 for idx, val in enumerate(nums): if val is not None and val > max_val: max_val, max_idx = val, idx ans.append((max_idx, max_val)) nums[max_idx] = None # 标记已选元素 # 按索引排序后提取值 return [val for idx, val in sorted(ans)] ``` --- #### 2. 堆(优先队列)优化法 **思路**:利用最大堆快速获取前 $k$ 个最大元素及其索引,再按索引排序恢复原始顺序。 - **时间复杂度**:$O(n \log n + k \log k)$,适合 $k$ 较大的情况。 - **空间复杂度**:$O(n)$。 ```python import heapq def maxSubsequence(nums, k): # 将元素索引存入堆,按值降序排列 heap = [(-val, idx) for idx, val in enumerate(nums)] heapq.heapify(heap) # 取前k个元素(值最大的k个) selected = [] for _ in range(k): val, idx = heapq.heappop(heap) selected.append((idx, -val)) # 按索引排序后提取值 selected.sort() return [val for idx, val in selected] ``` --- ### 关键点对比 | 方法 | 适用场景 | 时间复杂度 | 空间复杂度 | |--------------|------------------|------------------|------------| | 选择排序法 | $k$ 较小 | $O(nk)$ | $O(1)$ | | 堆优化法 | $k$ 较大或通用 | $O(n \log n)$ | $O(n)$ | --- ### 典型用例 1. **输入**:$nums = [3,1,4,2], k = 2$ **输出**:$[3,4]$(子序列索引为02,为7) 2. **输入**:$nums = [5,3,5,2], k = 2$ **输出**:$[5,5]$(索引02,为10) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值