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

最长上升子序列(一)

http://www.nowcoder.com/practice/5164f38b67f846fb8699e9352695cd2f

题目主要信息:
  • 给定一个数组,求其中最长的严格上升子序列的长度
  • 子序列是指数组去掉或不去掉元素后的数组,不要求在原本数组中全部相邻,但是在原数组中的相对位置不能改变
  • 严格上升指子序列严格单调递增
举一反三:

学习完本题的思路你可以解决如下题目:

BM65 最长公共子序列(二)

BM66.最长公共子串

BM73 最长回文子串

BM75 编辑距离(一)

BM76 正则表达式匹配

BM77 最长的括号子串

方法:动态规划(推荐使用)

知识点:动态规划

动态规划算法的基本思想是:将待求解的问题分解成若干个相互联系的子问题,先求解子问题,然后从这些子问题的解得到原问题的解;对于重复出现的子问题,只在第一次遇到的时候对它进行求解,并把答案保存起来,让以后再次遇到时直接引用答案,不必重新求解。动态规划算法将问题的解决方案视为一系列决策的结果

思路:

要找到最长的递增子序列长度,每当我们找到一个位置,它是继续递增的子序列还是不是,它选择前面哪一处接着才能达到最长的递增子序列,这类有状态转移的问题常用方法是动态规划。

具体做法:

  • step 1:用dp[i]dp[i]表示到元素ii结尾时,最长的子序列的长度,初始化为1,因为只有数组有元素,至少有一个算是递增。
  • step 2:第一层遍历数组每个位置,得到n个长度的子数组。
  • step 3:第二层遍历相应子数组求对应到元素ii结尾时的最长递增序列长度,期间维护最大值。
  • step 4:对于每一个到ii结尾的子数组,如果遍历过程中遇到元素j小于结尾元素,说明以该元素结尾的子序列加上子数组末尾元素也是严格递增的,因此转移方程为dp[i]=dp[j]+1dp[i] = dp[j] + 1

图示:

alt

Java实现代码:

import java.util.*;
public class Solution {
    public int LIS (int[] arr) {
        int[] dp = new int[arr.length];
        //设置数组长度大小的动态规划辅助数组
        Arrays.fill(dp, 1); 
        int res = 0;
        for(int i = 1; i < arr.length; i++){
            for(int j = 0; j < i; j++){
                //可能j不是所需要的最大的,因此需要dp[i] < dp[j] + 1
                if(arr[i] > arr[j] && dp[i] < dp[j] + 1){
                    //i点比j点大,理论上dp要加1
                    dp[i] = dp[j] + 1; 
                    //找到最大长度
                    res = Math.max(res, dp[i]); 
                }
            }
        }
        return res;
    }
}

C++实现代码:

class Solution {
public:
    int LIS(vector<int>& arr) {
        //设置数组长度大小的动态规划辅助数组
        vector<int> dp(arr.size(), 1); 
        int res = 0;
        for(int i = 1; i < arr.size(); i++){
            for(int j = 0; j < i; j++){
                //可能j不是所需要的最大的,因此需要dp[i] < dp[j] + 1
                if(arr[i] > arr[j] && dp[i] < dp[j] + 1) {
                    //i点比j点大,理论上dp要加1
                    dp[i] = dp[j] + 1; 
                    //找到最大长度
                    res = max(res, dp[i]); 
                }
            }
        }
        return res;
    }
};

Python代码实现:

class Solution:
    def LIS(self , arr: List[int]) -> int:
        #设置数组长度大小的动态规划辅助数组
        dp = [1 for i in range(len(arr))] 
        res = 0
        for i in range(1, len(arr)):
            for j in range(i):
                #可能j不是所需要的最大的,因此需要dp[i] < dp[j] + 1
                if arr[i] > arr[j] and dp[i] < dp[j] + 1: 
                    #i点比j点大,理论上dp要加1
                    dp[i] = dp[j] + 1 
                    #找到最大长度
                    res = max(res, dp[i]) 
        return res

复杂度分析:

  • 时间复杂度:O(n2)O(n^2),其中nn为数组长度,两层遍历循环
  • 空间复杂度:O(n)O(n),辅助数组dp的空间
全部评论
res初值设为1,不然好像不能通过[1,1,1,1,1]
3 回复 分享
发布于 2022-09-02 22:41 江苏
官方题解有特例没有通过,这就离谱了
1 回复 分享
发布于 2022-11-22 19:33 四川
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 给定数组的最长严格上升子序列的长度。 * @param arr int整型一维数组 给定的数组 * @return int整型 */ public int LIS (int[] arr) { int length = arr.length; if (arr == null || length == 0) { return 0; } int[] dp = new int[length]; Arrays.fill(dp, 1); int res = 1; for (int i = 1; i < length ; i++) { for (int j = 0; j < i ; j++) { // j位置到i递增,但未必最大 if (arr[i] > arr[j] && dp[i] < dp[j] + 1) { dp[i] = dp[j] + 1; res = Math.max(res, dp[i]); } } } return res; } }
1 回复 分享
发布于 2023-04-09 23:35 重庆
呃~ 官方题解c++的有错!
1 回复 分享
发布于 2023-08-04 12:25 山东
条件dp[i] < dp[j] + 1是关键。 可以这样理解,更新后得到的最大的dp[i]不应该再次被修改。 理论上,dp[i]的最大值就是不超过dp[j]+1。
点赞 回复 分享
发布于 2022-10-05 20:24 美国
答案有过不了的测试用例。
点赞 回复 分享
发布于 2022-10-13 21:01 江苏
官解过不了测试用例 笑话
点赞 回复 分享
发布于 2023-03-21 13:36 江苏
官方通过版
点赞 回复 分享
发布于 2023-04-09 23:35 重庆
没有任何逻辑性,纯属拼凑答案
点赞 回复 分享
发布于 2023-04-20 18:58 广东
下面是个人理解官方答案和修改的版本,保过测试集。在各位大佬面前班门弄斧了哈。 #include <algorithm> #include <vector> class Solution { public: int LIS(vector<int>& arr) { // write code here if(arr.size() < 1){ return 0;}//这里补充一下官方答案的缺陷 if(arr.size() == 1){ return 1;}//这里补充一下官方答案的缺陷 vector<int> laborer(arr.size(), 1);//用于动态维护的数组 int result = 0; //最终要返回的结果,需要维护更新result = max(result, laborer[i]) for(int i = 0; i < arr.size(); i++){ for(int j = 0; j < i; j++){//每次与前方元素比较,时间<n> arr[j] && laborer[j] +1 > laborer[i]){ //前方元素的长度+1后就是当前的长度 laborer[i] = laborer[j] + 1; result = max(result, laborer[i]);//维护 } } } return result; } };</n></int></int></vector></algorithm>
点赞 回复 分享
发布于 2023-05-18 11:55 广东
这样运行有错的,可以这样小改 ``` class Solution { public: int LIS(vector<int>& arr) { if(arr.empty()) return 0; //设置数组长度大小的动态规划辅助数组 vector<int> dp(arr.size(), 1); int res = 1; for(int i = 1; i < arr.size(); i++){ for(int j = 0; j < i; j++){ //可能j不是所需要的最大的,因此需要dp[i] < dp[j] + 1 if(arr[i] > arr[j] && dp[i] < dp[j] + 1) { //i点比j点大,理论上dp要加1 dp[i] = dp[j] + 1; //找到最大长度 res = max(res, dp[i]); } } } return res; } }; ```</int></int>
点赞 回复 分享
发布于 2023-08-17 21:06 广东
这个空间和时间,也能上精华吗
点赞 回复 分享
发布于 02-29 22:20 北京
官方真不负责
点赞 回复 分享
发布于 02-29 22:42 北京
需要新加一个if(arr.length==0) return 0; 还需要更改一个 res=1;
点赞 回复 分享
发布于 03-15 20:09 湖南
public int LIS (int[] arr) { // write code here if (arr.length == 0) return 0; int[] dp = new int[arr.length]; Arrays.fill(dp, 1); int res = 1; for (int i = 0; i < arr.length; i++) { for (int j = 0; j < i; j++) { if (arr[i] > arr[j]) { dp[i] = Math.max (dp[i], dp[j] + 1); res = Math.max(res, dp[i]); } } } return res; }
点赞 回复 分享
发布于 06-28 18:08 北京

相关推荐

10-14 23:01
已编辑
中国地质大学(武汉) Java
CUG芝士圈:虽然是网上的项目,但最好还是包装一下,然后现在大部分公司都在忙校招,十月底、十一月初会好找一些。最后,boss才沟通100家,别焦虑,我去年暑假找第一段实习的时候沟通了500➕才有面试,校友加油
点赞 评论 收藏
分享
16 4 评论
分享
牛客网
牛客企业服务