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

// 作者:灵茶山艾府
相关推荐
劲夫学编程42 分钟前
leetcode:杨辉三角
算法·leetcode·职场和发展
毕竟秋山澪44 分钟前
孤岛的总面积(Dfs C#
算法·深度优先
浮生如梦_3 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
励志成为嵌入式工程师5 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
师太,答应老衲吧5 小时前
SQL实战训练之,力扣:2020. 无流量的帐户数(递归)
数据库·sql·leetcode
捕鲸叉5 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer5 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
wheeldown6 小时前
【数据结构】选择排序
数据结构·算法·排序算法
观音山保我别报错7 小时前
C语言扫雷小游戏
c语言·开发语言·算法
TangKenny8 小时前
计算网络信号
java·算法·华为