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

最长上升子序列(三)

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

C++, 贪心 + 二分查找

设置一个记录上升子序列状态的二维dp[n + 1][ ];

vector<vector> dp_str(n + 1, vector ());
第一维下标代表当前长度,其第二维代表最长子序列

贪心思想:若想让子序列长度更长,则应确保每次增加新元素的幅度尽可能的小,“小步多走”;

从头遍历数组,寻找 ==以当前元素为最后元素== 的上升子序列;

  1. 若 当前元素 > 当前最长子序列的最后一个元素,则添加并更新最长子序列;
  2. 若 当前元素 <= 当前最长子序列的最后一个元素, 则其可以替代当前最长子序列中间的某一个元素,为后面的上升序列做铺垫
    • 二分查找 在当前最长子序列中 查找 【第一个小于当前元素的元素位置pos】,并在其后替换更新
    • 按字典顺序大小 比较 【新取得的子序列temp 】 与 【已有的同长度的子序列dp_str[pos + 1]】 哪个更小,保留字典序列小的;
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
        int n = arr.size();
        // 第一维下标代表当前长度,其第二维代表最长子序列
        vector<vector<int>> dp_str(n + 1, vector<int> ());
        // 初始化第一个长度为1的开始子序列
        int len = 1; 
        dp_str[len].emplace_back(arr[0]);

        for (int i = 1; i < n; ++i) {
            // 若 当前元素 > 当前最长子序列的最后一个元素,则添加并更新最长子序列
            if (arr[i] > dp_str[len].back()) {
                ++len;
                dp_str[len] = dp_str[len - 1];
                dp_str[len].emplace_back(arr[i]);
            }
            // 若 当前元素 < 当前最长子序列的最后一个元素, 则其可以替代最长子序列中间的某一个元素
            else {
                // 二分查找 在当前最长子序列中 查找 第一个小于当前元素的元素位置,并更新
                int l = 1, r = len, pos = 0;
                while (l <= r) {
                    int mid = l + ((r - l) >> 1);
                    if (dp_str[mid].back() < arr[i]) {
                        l = mid + 1;
                        pos = mid;
                    }
                    else {
                        r = mid - 1;
                    }
                }
                // temp 为 若成功替换后,新的以arr[i]结尾,长度为pos + 1 的子序列
                vector<int> temp = dp_str[pos];
                temp.emplace_back(arr[i]);
                // 与以及存在的 同长度的 子序列 按字典大小比较,若新的更小,则更新
                if (temp < dp_str[pos + 1]) {
                    dp_str[pos + 1] = temp;
                } 
//                 // 否则, 只更新最后一个元素
//                 else {
//                     dp_str[pos + 1].back() = arr[i];
//                 }
            }
        }
        return dp_str[len];
    }
};
全部评论
行行有大神
1 回复 分享
发布于 2022-10-22 18:56 陕西

相关推荐

点赞 评论 收藏
分享
08-29 07:47
已编辑
莆田学院 Java
路上小荷:小孙,你好,我是由XX幼儿园、XX小学、XX初中、XX高中、XX大***合培养的研究生,想寻找能够陪我一起成长,登上人生巅峰的公司。在公司任职期间公司需要提供免费食宿、百万年薪以及私人医生。预计65岁退休,退休后公司可以求我给新员工讲述奋斗历程
点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务