2386. 找出数组的第 K 大和

377 阅读1分钟

题目描述

给你一个整数数组 nums 和一个 整数 k 。你可以选择数组的任一 子序列 并且对其全部元素求和。

数组的 第 k 大和 定义为:可以获得的第 k最大 子序列和(子序列和允许出现重复)

返回数组的 第 k 大和

子序列是一个可以由其他数组删除某些或不删除元素排生而来的数组,且派生过程不改变剩余元素的顺序。

注意: 空子序列的和视作 0

解题思路

  • 从最大值入手,算出所有非负整数的和记为tx
  • 下一个最大值为前一个最大值减去一个子集或者加上一个负子集
  • 如何对负数进行处理,在求出最大值后,将负数取绝对值

如何取绝对值后的子集呢?

答案就是01枚举

  • 取绝对值前 | 下标 | 0 |1|2| | --- | --- || --- | --- | |数值 | 1 |-2| 4 |

  • 取绝对值后并排序 | 下标 | 0 |1|2| | --- | --- || --- | --- | |数值 | 1 |2| 4 |

  • 01枚举

graph TD
x0[0] --> x1[0] -->x2[0]
sum为tx-0
x3[1] --> x4[0] -->x5[0]
sum为tx-1
x6[1] --> x7[1] -->x8[0]
sum为tx-1-2

  • 利用堆的思想将最大值放于堆顶priority_queue优先队列

  • priority_queue的设计与实现就是用堆实现的

  • 堆上存有最值和下一个数的下标,每一个下标都有两个选项,---[选|不选]

  • 减去下一个加上上一个

class Solution {
public:
    long long kSum(vector<int>& nums, int k) {
        long long tx=0;
        for(int i=0;i<nums.size();i++){
            if(nums[i]>=0)tx+=nums[i];
            else nums[i]=-nums[i];
        }
        sort(nums.begin(),nums.end());
        priority_queue<pair<long long,int>>q;
        q.push(make_pair(tx,0));
        while(k>1){
            k--;
            auto [a,b]=q.top();q.pop();
           // cout<<a<<" "<<b<<endl;
            if(b>=nums.size())continue;
            q.push(make_pair(a-nums[b],b+1));
            if(b)q.push(make_pair(a-nums[b]+nums[b-1],b+1));
        }
        tx=q.top().first;
        return tx;
    }
};