leetcode 2542. Maximum Subsequence Score(最大子串分数)-LMLPHP

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; 
}
05-24 22:32