力扣每日一题 找出数组的第 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); // 不选
    }
}

// 作者:灵茶山艾府
相关推荐
寂静山林13 小时前
UVa 1366 Martian Mining
算法
陌路2014 小时前
S12 简单排序算法--冒泡 选择 直接插入 希尔排序
数据结构·算法·排序算法
音视频牛哥14 小时前
从 SmartMediaKit 设计探讨音视频工程师的面试与能力评估框架
程序人生·职场和发展·音视频·rtsp播放器·rtmp播放器·音视频工程师面试·音视频程序员面试题
雾岛—听风14 小时前
P1012 [NOIP 1998 提高组] 拼数
算法
papership15 小时前
【入门级-算法-5、数值处理算法:高精度的乘法】
数据结构·算法
earthzhang202115 小时前
【1039】判断数正负
开发语言·数据结构·c++·算法·青少年编程
谈笑也风生15 小时前
只出现一次的数字 II(一)
数据结构·算法·leetcode
蕓晨15 小时前
auto 自动类型推导以及注意事项
开发语言·c++·算法
mjhcsp15 小时前
C++ 递推与递归:两种算法思想的深度解析与实战
开发语言·c++·算法
_OP_CHEN16 小时前
算法基础篇:(三)基础算法之枚举:暴力美学的艺术,从穷举到高效优化
c++·算法·枚举·算法竞赛·acm竞赛·二进制枚举·普通枚举