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++
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
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); // 不选
    }
}

相关推荐

  1. 每日】01

    2024-03-15 22:12:03       6 阅读
  2. leetcode每日4

    2024-03-15 22:12:03       39 阅读
  3. leetcode每日37

    2024-03-15 22:12:03       41 阅读

最近更新

  1. github 下载提速的几种方法

    2024-03-15 22:12:03       0 阅读
  2. 交替打印-GO

    2024-03-15 22:12:03       0 阅读
  3. 秒验 iOS端如何修改授权页背景

    2024-03-15 22:12:03       1 阅读
  4. 探索HTML5的设计原则:引领Web开发的未来方向

    2024-03-15 22:12:03       1 阅读
  5. hive 调优

    2024-03-15 22:12:03       1 阅读
  6. 精通C#编程需要学习哪些常用框架?

    2024-03-15 22:12:03       1 阅读

热门阅读

  1. mysql binlog自动删除与手动删除

    2024-03-15 22:12:03       21 阅读
  2. 老卫带你学---leetcode刷题(189. 轮转数组)

    2024-03-15 22:12:03       20 阅读
  3. 【算法-特征选择】reliefF算法实现

    2024-03-15 22:12:03       22 阅读
  4. 百科 | 光伏电站如何开展运维工作?

    2024-03-15 22:12:03       23 阅读
  5. BUG解决-Modelsim打开许可证件不可用

    2024-03-15 22:12:03       19 阅读
  6. go反射实战

    2024-03-15 22:12:03       17 阅读
  7. Python中的pip工具

    2024-03-15 22:12:03       19 阅读
  8. 为什么会出现粘包这个问题

    2024-03-15 22:12:03       18 阅读
  9. 26: 翻转数的和(python)

    2024-03-15 22:12:03       24 阅读