题解 | #最长上升子序列(三)#

最长上升子序列(三)

https://www.nowcoder.com/practice/9cf027bf54714ad889d4f30ff0ae5481

解题思路:

创建一个dp的二维数组(n*3)

创建一个由优先队列(最小堆)组成的数组v

样例:

dp[i][0]: 2 1 5 3 6 4 8 9 7

dp[i][1]: 1 1 2 2 3 3 4 5 4

dp[i][2]: 0 0 1 1 3 3 4 8 4

dp[i][0]:arr[i]

dp[i][1]:到第i个元素时,包含该元素的最长的子序列长度

dp[i][2]:到第i个元素时,包含该元素的最长的子序列中,倒数第二个元素

dp[i][1]的计算方法:

获得当前元素arr[i]

从大到小地遍历现有的优先队列数组,找到第一个合适的(当前元素大于该优先队列的最小值)优先队列;

找到合适的优先队列等于知道了加上当前元素,子序列的最大长度k,

然后将该元素插入到v[k-1]中(v[k-1]为以所有子序列中,第k个元素的最小堆,

如样例中的最小堆有(2,1),(5,3),(6,4),(8,7),(9)

)

dp[i][2]的计算方法:

计算dp[i][1]时,找到的合适的优先队列的堆顶元素就是dp[i][2]

得到dp数组后,

先找到dp二维数组中,dp[i][1]为最大并且dp[i][0]最小的一维数组,

将目标元素dp[i][0]存放在最终答案 answer中

并且将i的位置记为position,

将dp[i][1](长度)记为maxn ,

将dp[i][2](子序列中前一个元素)记为target

然后从i向v.begin()遍历找到长度为maxn-1并且当前元素为target的元素

将当前元素存放进answer中,并且更新maxn和target

最后反转answer得到最终答案

#include <algorithm>
#include <climits>
#include <functional>
#include <queue>
#include <utility>
class Solution {
public:
    /**
     * retrun the longest increasing subsequence
     * @param arr int整型vector the array
     * @return int整型vector
     */
    vector<int> LIS(vector<int>& arr) {
        // write code here
        vector<int> answer;
        if(arr.size() == 0){
            return answer;
        }
        vector<priority_queue<int,vector<int>, greater<int> > > vp; //用优先队列保存相等的子序列
        priority_queue<int,vector<int>, greater<int> > first;
        vector<vector<int> > dp;                                    //第一个int为arr里的元素
                                                                    //第二个int为包括该元素的最长子序列长度
        first.push(arr[0]);
        vp.push_back(first);
        vector<int> t = {arr[0],1,0};
        dp.push_back(t);
        for(int i = 1 ; i < arr.size() ; i++){                      //遍历arr中的每一个元素
            int j;
            int pre;
            for(j = vp.size()-1; j >= 0; j--){                      //从大到小遍历每个优先队列,每个优先队列的队头都是最小值
                                                                    //找到的第一个值一定是最大长度队列中的最小值
                if(arr[i]>vp[j].top()){
                    pre = vp[j].top();
                    if(j == vp.size()-1){                           //如果第一个队列就是目标队列,说明遇到新的最大长度
                        priority_queue<int,vector<int>, greater<int> > now;
                        now.push(arr[i]);
                        vp.push_back(now);
                        break;
                    }else{                                          //否则将该元素插入到已有队列中
                        vp[j+1].push(arr[i]);
                        break;
                    }    
                }
            }
            vector<int> t;
            if(j != -1){                                            //如果找到了目标队列,则记录该元素的最长子序列长度
                t = {arr[i],j+2,pre};                       
                dp.push_back(t);   
            }else{                                                  //没找到,说明其比之前所有元素都小,其子序列长度为1
                t = {arr[i],1,0};
                dp.push_back(t);
                vp[0].push(arr[i]);
            }
        }
        int maxn = 0;                                               //长度
        int now = INT_MAX;                                          //相同长度下,元素的最小值
        int target;                                                 //前一个目标元素
        int ii;                                                     //目标元素的下标
        for(int i = dp.size()-1 ; i >=0 ; i--){                     //先找到最大长度下的最小值及其下标
            if(maxn == dp[i][1] && now > dp[i][0]){
                now = dp[i][0];
                target = dp[i][2];
                ii = i;
            }
            if(maxn < dp[i][1]){
                maxn = dp[i][1];
                now = dp[i][0];
                target = dp[i][2];
                ii = i;
            }
        }
        answer.push_back(now);
        now  = INT_MAX;
        maxn--;
        for(int j = ii ; j >=0 ; j--){                              //找下一个目标元素
            if(dp[j][1] == maxn && dp[j][0] == target){
                answer.push_back(target);
                target = dp[j][2];
                maxn--;
            }
        }
        reverse(answer.begin(), answer.end());
        return answer;


    }
};

全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务