2024.3.9每日一题

LeetCode

找出数组的第 K 大和

题目链接:2386. 找出数组的第 K 大和 - 力扣(LeetCode)

题目描述

给你一个整数数组 nums 和一个 整数 k 。你可以选择数组的任一 子序列 并且对其全部元素求和。

数组的 第 k 大和 定义为:可以获得的第 k最大 子序列和(子序列和允许出现重复)

返回数组的 第 k 大和

子序列是一个可以由其他数组删除某些或不删除元素排生而来的数组,且派生过程不改变剩余元素的顺序。

**注意:**空子序列的和视作 0

示例 1:

复制代码
输入:nums = [2,4,-2], k = 5
输出:2
解释:所有可能获得的子序列和列出如下,按递减顺序排列:
- 6、4、4、2、2、0、0、-2
数组的第 5 大和是 2 。

示例 2:

复制代码
输入:nums = [1,-2,3,4,-10,12], k = 16
输出:10
解释:数组的第 16 大和是 10 。

提示:

  • n == nums.length
  • 1 <= n <= 105
  • -109 <= nums[i] <= 109
  • 1 <= k <= min(2000, 2n)

思路

困难题 cv大法

灵神题解

代码

C++
C++ 复制代码
class Solution {
public:
    long long kSum(vector<int> &nums, int k) {
        long sum = 0;
        for (int &x : nums) {
            if (x >= 0) {
                sum += x;
            } else {
                x = -x;
            }
        }
        ranges::sort(nums);

        auto check = [&](long sum_limit) -> bool {
            int cnt = 1; 
            function<void(int, long long)> dfs = [&](int i, long long s) {
                if (cnt == k || i == nums.size() || s + nums[i] > sum_limit) {
                    return;
                }
                cnt++; // s + nums[i] <= sum_limit
                dfs(i + 1, s + nums[i]);
                dfs(i + 1, s); 
            };
            dfs(0, 0);
            return cnt == k; 
        };

        long long left = -1, right = accumulate(nums.begin(), nums.end(), 0LL);
        while (left + 1 < right) { 
            long long mid = (left + right) / 2;
            (check(mid) ? right : left) = mid;
        }
        return sum - right;
    }
};
Java
java 复制代码
class Solution {
    public long kSum(int[] nums, int k) {
        long sum = 0, right = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] >= 0) {
                sum += nums[i];
            } else {
                nums[i] = -nums[i];
            }
            right += nums[i];
        }
        Arrays.sort(nums);

        long left = -1;
        while (left + 1 < right) { // 开区间二分,原理见【前置知识】
            long mid = (left + right) / 2;
            cnt = k - 1; // 空子序列算一个
            dfs(0, mid, nums);
            if (cnt == 0) { // 找到 k 个元素和不超过 mid 的子序列
                right = mid;
            } else {
                left = mid;
            }
        }
        return sum - right;
    }

    private int cnt;

    // 反向递归,增加改成减少,这样可以少传一些参数
    private void dfs(int i, long s, int[] nums) {
        if (cnt == 0 || i == nums.length || s < nums[i]) {
            return;
        }
        cnt--;
        dfs(i + 1, s - nums[i], nums); // 选
        dfs(i + 1, s, nums); // 不选
    }
}
相关推荐
im_AMBER16 小时前
手撕hot100之矩阵!看完这篇就AC~
javascript·数据结构·线性代数·算法·leetcode·矩阵
笨笨饿17 小时前
#79_NOP()嵌入式C语言中内联汇编宏的抽象封装模式研究
linux·c语言·网络·驱动开发·算法·硬件工程·个人开发
风萧萧199917 小时前
问答样例如何在RAG问答中使用?
算法
七夜zippoe17 小时前
DolphinDB分区策略:HASH分区与COMPO分区
算法·哈希算法·hash·dolphindb·compo
沪漂阿龙18 小时前
程序员面试技术爆款文:2026大厂算法通关手册——从零基础到LeetCode刷穿,这一篇就够了
算法·leetcode·面试
rit843249919 小时前
基于博弈论的小区分簇算法MATLAB实现
开发语言·算法·matlab
华清远见成都中心19 小时前
C 语言内存管理深度解析:malloc/free 与嵌入式堆栈分配策略
java·c语言·算法
一行代码一行诗++19 小时前
关系操作符
算法
生成论实验室20 小时前
《源·觉·知·行·事·物:生成论视域下的统一认知语法》第五章 事:行在时空中的具体化
人工智能·算法·架构·知识图谱·创业创新
Liangwei Lin20 小时前
LeetCode 283. 移动零
算法