2个数组,长度一样,从中选k个下标(两个数组用同样的下标),
会得到k个nums1中的数字,和k个nums2中的数字。
score = k个nums1的数字之和 ✖ min(k个nums2的数字),
找到最大的score。
思路:
和1383题一样。
每次要和k个nums2的数字中最小的一个相乘。那每次肯定想尽量找大的nums2.
最好是优先取最大的nums2。
那么把nums1[i]和nums2[i]组成一对,作为元素,组成一个数组,按nums2排序。
这样遍历数组时优先取的是较大的nums2.
nums2降序以后,相当于把问题降了一维,现在剩下想取较大的nums1, 才能保证sum(k个nums1)较大。
在nums1的个数 > k个后,去掉其中最小的,更新sum, 个数=k时,更新score.
public long maxScore(int[] nums1, int[] nums2, int k) {
int n = nums1.length;
int[][] nums12 = new int[n][2];
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
long sum = 0;
long res = 0;
for(int i = 0; i < n; i++) {
nums12[i] = new int[]{nums1[i], nums2[i]};
}
Arrays.sort(nums12, (a, b)->(b[1]-a[1]));
for(int[] num : nums12) {
sum += num[0];
minHeap.offer(num[0]);
if(minHeap.size() > k) sum -= minHeap.poll();
if(minHeap.size() == k) res = Math.max(res, sum*num[1]);
}
return res;
}
还可以优化一下,上面方法是每个nums1都装进minHeap, 然后再考虑去掉,
现在考虑先装入k个数字,
如果后面nums1比minHeap中最小的元素都小,就不需要再装进去。省去一步。
public long maxScore(int[] nums1, int[] nums2, int k) {
int n = nums1.length;
int[][] nums12 = new int[n][2];
for(int i =0; i<n; i++){
nums12[i] = new int[]{nums1[i], nums2[i]};
}
Arrays.sort(nums12, (a,b)->(b[1]-a[1]));
long res = -1;
PriorityQueue<Integer> pq = new PriorityQueue<>(k);
long sum =0;
for(int i = 0; i < k; i++){
pq.add(nums12[i][0]);
sum += nums12[i][0];
}
res= Math.max(res, (sum * nums12[k-1][1]));
for(int i = k; i < n; i++){
int n1 = nums12[i][0];
if(n1 > pq.peek()){
sum -= pq.poll();
pq.add(n1);
sum += n1;
}
res= Math.max(res, (sum * nums12[i][1]));
}
return res;
}