给你一个整数数组 nums 和一个 正 整数 k 。你可以选择数组的任一 子序列 并且对其全部元素求和。
数组的 第 k 大和 定义为:可以获得的第 k 个 最大 子序列和(子序列和允许出现重复)
返回数组的 第 k 大和 。
子序列是一个可以由其他数组删除某些或不删除元素排生而来的数组,且派生过程不改变剩余元素的顺序。
注意:空子序列的和视作 0 。
class Solution {
/**
思路很厉害,先求最大值,然后对数组取绝对值进行排序,对新数组利用最小堆进行全排列
*/
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<Long, Integer>> pq = new PriorityQueue<>((a,b)->Long.compare(a.getKey(),b.getKey()));
pq.offer(new Pair<>(0L,0));
while(--k>0) {
Pair<Long,Integer> pair = pq.poll();
Long s = pair.getKey();
int i = pair.getValue();
if(i<n) {
pq.offer(new Pair<>(s+nums[i],i+1));
if(i>0) {
pq.offer(new Pair<>(s-nums[i-1]+nums[i], i+1));
}
}
}
return sum-pq.peek().getKey();
}
}
补充:PriorityQueue的用法
不指定Comparator时默认为最小堆,通过传入自定义的Comparator函数可以实现大顶堆。使用offer添加元素,使用poll取出元素。
最小堆:每次poll的时候,都是取最小值。
// 这个结构很常用
PriorityQueue<Pair<Long, Integer>> pq = new PriorityQueue<>((a,b)->Long.compare(a.getKey(),b.getKey()));