代码随想录算法训练营第五十二天 | 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组

Posted 好吃的蛋奶星星

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代码随想录算法训练营第五十二天 | 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组相关的知识,希望对你有一定的参考价值。

300. 最长递增子序列

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

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

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4

动规五部曲:

  1. 确定dp数组及其下标含义

dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度

  1. 确定递推公式

位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列 + 1 的最大值。

所以:if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);

  1. dp数组初始化

每一个i,对应的dp[i](即最长递增子序列)起始大小至少都是1

  1. 确定遍历顺序

外层遍历i,内层遍历j,从大到小遍历

  1. 举例推导dp数组

    nums=[0 1 0 3 2]

    dp[1]=[1 2 1 1 1]

    dp[2]=[1 2 1 1 1]

    dp[3]=[1 2 1 3 1]

    dp[4]=[1 2 1 3 3]

class Solution 
    public int lengthOfLIS(int[] nums) 
        if(nums.length==0||nums==null) return 0;
        int[] dp=new int[nums.length];
        Arrays.fill(dp,1);
        for(int i=0;i<nums.length;i++)
            for(int j=0;j<i;j++)
                if(nums[i]>nums[j])
                    dp[i]=Math.max(dp[i],dp[j]+1);
                
            
        
        int res=0;
        for(int i:dp)
            res=Math.max(res,i);
        
        return res;
    

674. 最长连续递增序列

给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。

连续递增的子序列 可以由两个下标 lrl < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] ,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列。

输入:nums = [1,3,5,4,7]
输出:3
解释:最长连续递增序列是 [1,3,5], 长度为3。
尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 57 在原数组里被 4 隔开。

动规五部曲:

  1. 确定dp数组及其下标含义

dp[i]表示下标i为结尾的连续递增子序列长度为dp[i]

  1. 确定递推公式

如果 nums[i] > nums[i - 1],那么以 i 为结尾的连续递增的子序列长度 一定等于 以i - 1为结尾的连续递增的子序列长度 + 1

dp[i+1]=dp[i]+1;

  1. dp数组初始化

dp[i]均初始化为1

  1. 确定遍历顺序

从前向后遍历

  1. 举例推导dp数组

    nums=[1 3 5 4 7]

    dp[0]=1

    dp[1]=2

    dp[2]=3

    dp[3]=1

    dp[4]=2

class Solution 
    public int findLengthOfLCIS(int[] nums) 
        int[] dp=new int[nums.length];
        Arrays.fill(dp,1);
        int res=1;
        for(int i=0;i<nums.length-1;i++)
            if(nums[i+1]>nums[i])
                dp[i+1]=dp[i]+1;
            
            res=res>dp[i+1]?res:dp[i+1];
        
        return res;
    

718. 最长重复子数组

给两个整数数组 nums1nums2,返回 两个数组中 公共的 、长度最长的子数组的长度

输入:nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7]
输出:3
解释:长度最长的公共子数组是 [3,2,1]
  1. 确定dp数组及其下标含义

dp[i][j]:以下标i-1为结尾的nums1,和以下标j-1为结尾nums2,最长重复子数组长度为dp[i][j]

  1. 确定递推公式

dp[i][j]=dp[i-1][j-1]+1

  1. dp数组初始化

将所有下标都默认初始化为0

  1. 确定遍历顺序

从前到后遍历

  1. 举例推导dp数组
class Solution 
    public int findLength(int[] nums1, int[] nums2) 
        int reslut=0;
        int[][] dp=new int[nums1.length+1][nums2.length+1];
        for(int i=1;i<=nums1.length;i++)
            for(int j=1;j<=nums2.length;j++)
                if(nums1[i-1]==nums2[j-1])
                    dp[i][j]=dp[i-1][j-1]+1;
                    reslut=Math.max(reslut,dp[i][j]);
                
            
        
        return reslut;
    

代码随想录算法训练营第五十八天|739.每日温度496.下一个更大元素Ⅰ

day58 2023/03/30

一、每日温度

请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。

例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。

分析如下:

要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了

单调栈的本质是空间换时间

在使用单调栈的时候首先要明确如下几点:

1.单调栈里存放的元素是什么?

单调栈里只需要存放元素的下标i就可以了,如果需要使用对应的元素,直接T[i]就可以获取。

2.单调栈里元素是递增呢? 还是递减呢?

注意以下讲解中,顺序的描述为 从栈头到栈底的顺序

使用单调栈主要有三个判断条件。

  • 当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
  • 当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况
  • 当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况

具体分析见代码随想录,分析的好透彻,好强 

代码如下:

class Solution 
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) 
     stack<int> st;
     vector<int> result(temperatures.size(),0);
     st.push(0);
     for(int i=1;i<temperatures.size();i++)
     
         if(temperatures[i]<temperatures[st.top()])
           st.push(i);
         else if(temperatures[i]==temperatures[st.top()])
           st.push(i);
        else
        
            while(!st.empty()&&temperatures[i]>temperatures[st.top()])
            
               result[st.top()]=i-st.top();
               st.pop();
            
            st.push(i);
        
     
     return result;
    
;

二、下一个更大元素Ⅰ

给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。

请你找出 nums1 中每个元素在 nums2 中的下一个比其大的值。

nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。

分析如下:

整体逻辑与上题相同,只是本题使用了一个map

代码如下:

class Solution 
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) 
        stack<int> st;
        vector<int> result(nums1.size(), -1);
        if (nums1.size() == 0) return result;

        unordered_map<int, int> umap; // key:下标元素,value:下标
        for (int i = 0; i < nums1.size(); i++) 
            umap[nums1[i]] = i;
        
        st.push(0);
        for (int i = 1; i < nums2.size(); i++) 
            if (nums2[i] < nums2[st.top()])            // 情况一
                st.push(i);
             else if (nums2[i] == nums2[st.top()])    // 情况二
                st.push(i);
             else                                     // 情况三
                while (!st.empty() && nums2[i] > nums2[st.top()]) 
                    if (umap.count(nums2[st.top()]) > 0)  // 看map里是否存在这个元素
                        int index = umap[nums2[st.top()]]; // 根据map找到nums2[st.top()] 在 nums1中的下标
                        result[index] = nums2[i];
                    
                    st.pop();
                
                st.push(i);
            
        
        return result;
    
;

以上是关于代码随想录算法训练营第五十二天 | 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组的主要内容,如果未能解决你的问题,请参考以下文章

代码随想录算法训练营第五十八天|739.每日温度496.下一个更大元素Ⅰ

代码随想录算法训练营第二天 | 977.有序数组的平方209.长度最小的子数组59.螺旋矩阵II

代码随想录算法训练营第二天 | 977.有序数组的平方209.长度最小的子数组59.螺旋矩阵II

代码随想录算法训练营第四十二天 | 01背包问题,你该了解这些01背包问题,你该了解这些 滚动数组 416. 分割等和子集

代码随想录算法训练营第五十天| 123. 买卖股票的最佳时机 III188. 买卖股票的最佳时机 IV。

代码随想录算法训练营第三十八天 | 理论基础 ,509. 斐波那契数,70. 爬楼梯,746. 使用最小花费爬楼梯