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

// 作者:灵茶山艾府
相关推荐
lifallen几秒前
深入浅出 Arrays.sort(DualPivotQuicksort):如何结合快排、归并、堆排序和插入排序
java·开发语言·数据结构·算法·排序算法
jingfeng5141 分钟前
数据结构排序
数据结构·算法·排序算法
能工智人小辰27 分钟前
Codeforces Round 509 (Div. 2) C. Coffee Break
c语言·c++·算法
kingmax5421200828 分钟前
CCF GESP202503 Grade4-B4263 [GESP202503 四级] 荒地开垦
数据结构·算法
岁忧33 分钟前
LeetCode 高频 SQL 50 题(基础版)之 【高级字符串函数 / 正则表达式 / 子句】· 上
sql·算法·leetcode
eachin_z1 小时前
力扣刷题(第四十九天)
算法·leetcode·职场和发展
闻缺陷则喜何志丹1 小时前
【强连通分量 缩点 拓扑排序】P3387 【模板】缩点|普及+
c++·算法·拓扑排序·洛谷·强连通分量·缩点
机器学习之心2 小时前
机器学习用于算法交易(Matlab实现)
算法·机器学习·matlab
AL流云。2 小时前
【优选算法】C++滑动窗口
数据结构·c++·算法
qq_429879673 小时前
省略号和可变参数模板
开发语言·c++·算法