力扣每日一题 找出数组的第 K 大和 小根堆 逆向思维(TODO:二分+暴搜)

Problem: 2386. 找出数组的第 K 大和

文章目录

  • 思路
  • 复杂度
  • [💖 小根堆](#💖 小根堆)
  • [💖 TODO:二分 + 暴搜](#💖 TODO:二分 + 暴搜)

思路

👨‍🏫 灵神题解


复杂度

时间复杂度:

添加时间复杂度, 示例: O ( n ) O(n) O(n)

空间复杂度:

添加空间复杂度, 示例: O ( n ) O(n) O(n)

💖 小根堆

Java 复制代码
class Solution {
	class Pair
	{
		long sum;
		int idx;

		public Pair(long x, int y)
		{
			super();
			this.sum = x;
			this.idx = y;
		}
	}

	public long kSum(int[] nums, int k)
	{
		long sum = 0;
		int n = nums.length;
		for (int i = 0; i < n; i++)
		{
			if (nums[i] >= 0)
				sum += nums[i];
			else
				nums[i] = -nums[i];
		}
		Arrays.sort(nums);
		PriorityQueue<Pair> heap = new PriorityQueue<>((a, b) -> Long.compare(a.sum, b.sum));
		heap.offer(new Pair(0L, 0));// 空子序列
//		一个不选也是一种情况
		while (--k > 0)// 注意:--k 比 k-- 要少一次循环
		{
			Pair p = heap.poll();
			long s = p.sum;
//			System.out.print(s + " "); //调试输出
			int i = p.idx;
			if (i < n)
			{
//				在子序列末尾添加 nums[i]
				heap.offer(new Pair(s + nums[i], i + 1));// 下一个要添加的元素下标为 i+1
				if (i > 0)// 替换子序列末尾元素为 nums[i]
					heap.offer(new Pair(s + nums[i] - nums[i - 1], i + 1));
			}
		}
//		heap.peek().sum 是第k小
//		sum 是第 1 大
		return sum - heap.peek().sum;
	}

}

💖 TODO:二分 + 暴搜

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

// 作者:灵茶山艾府
相关推荐
AndrewHZ5 分钟前
【三维渲染技术讨论】Blender输出的三维文件里的透明贴图在Isaac Sim里会丢失, 是什么原因?
算法·3d·blender·nvidia·贴图·具身智能·isaac sim
Y|5 分钟前
XGBoost(eXtreme Gradient Boosting,优化分布式梯度提升库)总结梳理
人工智能·算法·机器学习
啊我不会诶24 分钟前
【图论】最短路算法
算法·图论
前端梭哈攻城狮37 分钟前
js计算精度溢出,自定义加减乘除类
前端·javascript·算法
独行soc1 小时前
2025年渗透测试面试题总结-38(题目+回答)
android·安全·网络安全·面试·职场和发展·渗透测试·求职
秋难降1 小时前
深入解析快速排序:原理、波动根源与优化之道
算法·排序算法·编程语言
睡不醒的kun1 小时前
leetcode算法刷题的第二十一天
数据结构·c++·算法·leetcode·职场和发展·回溯算法·回归算法
小欣加油1 小时前
leetcode 461 汉明距离
c++·算法·leetcode
一起努力啊~3 小时前
算法题打卡力扣第169题:多数元素(easy)
算法·leetcode·哈希算法
水冗水孚3 小时前
通俗易懂地理解深度遍历DFS、和广度遍历BFS
javascript·算法