zoukankan      html  css  js  c++  java
  • 最长递增子序列-DP+打牌

    题目

    300. 最长递增子序列

    难度中等1533

    给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

    子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

    示例 1:

    输入:nums = [10,9,2,5,3,7,101,18]
    输出:4
    解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
    提示:
    	1 <= nums.length <= 2500
    	-104 <= nums[i] <= 104
    

    子串 VS 子序列

    1. 子串:一定是连续的

    2. 子序列可以不用连续,但是要注意元素原来的相对顺序。

      (大白话就是:在你前面的还是在你前面。术语叫做:稳定!)

    解法一:动态规划

    动态规划解法思想:

    1. 找到状态和选择
    2. 明确dp数组、函数的定义 (在本题中:dp[i] 表示以nums[i]这个数结尾的最长递增子序列的长度)
    3. 寻找状态之间的关系 (经常会使用数学归纳法)
    /**
     * @param {number[]} nums
     * @return {number}
     */
    var lengthOfLIS = function(nums) {
      // base case: 最长递增子序列初始值为1,就是要包括自己
        const dp = new Array(nums.length);
        dp.fill(1);
      
        for(let i = 0; i < nums.length; ++i) {
            // 找到在i前面比nums[i]小的数字
            for(let j = 0; j < i; ++j  ) {
              // 找到比nums[i]小的书,形成新的递增子序列,新的递增子序列在原来的基础上加1
                if (nums[i] > nums[j]) {
                    dp[i] = Math.max(dp[i],dp[j] + 1);
                }
            }
        }
      	// apply这函数挺好用的,可以用来改变参数的传递。
        return Math.max.apply(Math,dp);
    };
    

    解法二:二分搜索

    解法核心思想:
    给牌分堆:

    var lengthOfLIS = function(nums) {
        let top = [];
        let piles = 0; // 记录牌的堆数
    
        for (let i = 0; i < nums.length; ++i) {
            // 当前牌,nums[i] 表示牌的大小
            let poker = nums[i];
    
            // 牌堆进行一个二分查找
            let left = 0,
                right = piles;
            while (left < right) {
                let mid = parseInt((left + right) / 2);
                if (top[mid] > poker) {
                    right = mid;
                } else if (top[mid] < poker) {
                    left = mid + 1;
                } else {
                    right = mid;
                }
            }
            if (left == piles) piles++;
            top[left] = poker;
        }
        return piles;
    };
    

    以上解法思想基本来自于 《labuladong算法小抄》,这是一本很”实在“, 可操作性强的书,十分适合菜鸟入门学习leetcode。

    刷leetcode的时候,大家要注意一个问题是,题不只是刷一遍,要完全理解一个问题至少刷个四五遍!而且还有一个问题是,你是来学习别人的解法的,你不会做,很正常!!不会就看题解,看官方题解,看图解题解,看labuladong题解,leetcode国际站题解!反正就是发掘一切能够学习的资料。如果你坐在那里半天耗一个题目完全没有必要,因为你不是来发明解法的!你是来学习解法的,学习别人优秀的解题思想的!

    参考

    - 《labuladong算法小抄》
    - leetcode官方题解
    慢慢来,比较快!基础要牢,根基要稳!向大佬致敬!
  • 相关阅读:
    第9课
    FreeRTOS 定时器组
    FMC—扩展外部 SDRAM
    FreeRTOS 事件标志组
    第8课
    FreeRTOS 系统时钟节拍和时间管理
    第七课 线性表的顺序存储结构
    手把手教你调试Linux C++ 代码(一步到位包含静态库和动态库调试)
    Windows GUI代码与Windows消息问题调试利器
    谈谈数据挖掘和机器学习
  • 原文地址:https://www.cnblogs.com/rookie123/p/14668604.html
Copyright © 2011-2022 走看看