• 微软面试题: LeetCode 300. 最长递增子序列 出现次数:2


    题目描述:

     解析:

    参考 VV大神 的题解:

    https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/dong-tai-gui-hua-er-fen-cha-zhao-tan-xin-suan-fa-p/

    方法一: 动态规划    

    //dp time: O(n^2)   memory :O(n)
    1. 定义状态:

      基于「动态规划」的状态设计需要满足「无后效性」的设计思想,可以将状态定义为「以 nums[i] 结尾 的「上升子序列」的长度」。

    「无后效性」的设计思想:让不确定的因素确定下来,以保证求解的过程形成一个逻辑上的有向无环图。这题不确定的因素是某个元素是否被选中,

    而我们设计状态的时候,让 nums[i] 必需被选中,这一点是「让不确定的因素确定下来」,也是我们这样设计状态的原因。

     
    2. 状态转移方程:

           如果一个较大的数接在较小的数后面,就会形成一个更长的子序列。只要 nums[i] 严格大于在它位置之前的某个数,那么 nums[i] 就可以接在

    这个数后面形成一个更长的上升子序列。

    3. 初始化:

    dp[i] = 111 个字符显然是长度为 11 的上升子序列。

    4. 输出:

    状态数组 dp 的最大值。

    5  空间优化:

    遍历到一个新数的时候,之前所有的状态值都得保留,因此无法优化空间。

    代码:

     1 //dp time: O(n^2)   memory :O(n)
     2     int lengthOfLIS(vector<int>& nums)
     3     {
     4         int res = 1;
     5         vector<int> dp(nums.size(),1);
     6         for(int i = 1; i < nums.size(); ++i)
     7         {
     8             for(int j = 0; j < i ;++j)
     9             {
    10                 if(nums[j] < nums[i])
    11                 {
    12                     dp[i] = max(dp[i],dp[j] + 1);
    13                 }
    14             }
    15             res = max(res,dp[i]);
    16         }
    17         return res;
    18     }

    方法二:dp  修改状态定义(同时用到了贪心算法、二分查找)

      状态设计思想:依然着眼于某个上升子序列的结尾的元素,如果已经得到的上升子序列的结尾的数越小,那么遍历的时候后面接上一个数,

    会有更大的可能构成一个长度更长的上升子序列。既然结尾越小越好,我们可以记录 在长度固定的情况下,结尾最小的那个元素的数值,这样定义

    以后容易得到「状态转移方程」。

         1 .定义新状态(特别重要)

    tail[i] 表示:长度为 i + 1 的 所有 上升子序列的结尾的最小值。

         数组 tail 也是一个严格上升数组。

        2. 状态初始化

      遍历第 1 个数 nums[0],直接放在有序数组 tail 的开头 tail[0] = nums[0]

        3.状态转移

    3.1  在遍历数组 nums 的过程中,看到一个新数 num,如果这个数 严格 大于有序数组 tail 的最后一个元素,就把 num 放在有序数组 tail 的后面,否则进入第 2 点;

    3.2  在有序数组 tail 中查找第 1 个等于大于 num 的那个数,用新数 num 替换;

       4. 输出:

    有序数组 tail 的长度,就是所求的「最长上升子序列」的长度。

       5. 空间优化:

    无法优化空间。

     1 //dp time: O(n*logn)   memory :O(n)
     2     int lengthOfLIS(vector<int>& nums)
     3     {
     4         //tail[i]:当前长度为 i+1 的递增子序列中,结尾元素最小的递增子序列的结尾元素值
     5         vector<int> tail;
     6         tail.push_back(nums[0]);
     7         for(int i = 1; i < nums.size(); ++i)
     8         {
     9             if(nums[i] > tail.back())
    10             {
    11                 tail.push_back(nums[i]);
    12             }
    13             else
    14             {
    15                 int j = std::lower_bound(tail.begin(),tail.end(),nums[i]) - tail.begin();
    16                 tail[j] = nums[i];
    17             }  
    18         }
    19         return tail.size();
    20     }
  • 相关阅读:
    图形2d,3d加速简介
    [转]startx启动过程分析
    initrd.img、vmlinux和 vmlinuz
    TSQL建主键索引语句 / 外键
    ASP.NET MVC 2.0在WinXP IIS6下的部署
    update中加入select
    Request
    jqGrid使用总结
    Jquery 表单取值赋值 处理返回json数据
    108个搞笑经典短句(转)
  • 原文地址:https://www.cnblogs.com/wangxf2019/p/14642082.html
Copyright © 2020-2023  润新知