首页 > 其他分享 >最长递增子序列

最长递增子序列

时间:2022-12-29 22:45:31浏览次数:45  
标签:剪枝 数字 int 递增 初始值 最大值 序列 最长

目录

题目

给你一个整数数组 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 。

示例 2:

输入:nums = [0,1,0,3,2,3]
输出:4

示例 3:

输入:nums = [7,7,7,7,7,7,7]
输出:1

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-increasing-subsequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路,粗暴的递归动态规划解法

做题时的全部思路,是一边做一边写的。

  • 这里的思路全是我做题时写的,可以清楚看出我是怎么得出结果的,感觉应该有帮助,所以就直接CV出来了。

  • 如果只想看题解的思路的话,直接看代码吧,我会用注释详细说明的。

  • //1.当i+1>i的时候,递增子序列的个数+1,且此时子序列的最小值为i+1

  • //2.题目就是,选取限定范围内,大于n的最小值,一共选取的次数,就是子序列的长度

  • //3.则需要的状态有,上一个最小值,此时的最小值,此时子序列的长度

  • //当i大于此时的最小值,长度+1,最小值为i。

  • //当i<此时的最小值,大于上一个最小值,则i为最小值,长度不变

  • //直到找到最后的数字,输出长度。

  • //出错了,第一个数字开头不一定是最好的,所以得对每个开头都尝试一遍

  • //然后对比彼此的最长子序列,看哪个大输出哪个

  • //那么现在要思考的就是,要怎么剪枝?

  • //1.当最大值小于当前最大值后,就可以不必再计算这个数字开头了

  • //2.对每一个数字,记录使用该数字时的最大子序列长度。若下一次长度小于该长度,就可以不必再计算了

  • //再一次出错了,可能会出现这种情况,0...18个大于1的数字...1.2.5

  • //这样子的话,我原本的算法只对当前的两位数字进行了比较,就无法跳到那么后面了。

  • //果然还是用回传统的方式比较好吗

  • //也就是,对每个数字的每种可能都进行运算,然后对比得出最大值。

  • //运算函数。

  • //给出初始值,算出该初始值的最大子序列

  • //对每个数字为初始值计算一次

  • //对比得出最大子序列然后输出.

  • //算最大子序列的逻辑

  • //初始值为i的最大子序列,等于1+x的最大子序列。(x>i且x的排序在i后面)

  • //若x为空,则最大子序列为1。

  • //下一个问题,怎么得出最大子序列,现在这样只是得出了子序列罢了,返回的也只是最后的子序列,而非最大子序列

  • //显而易见的,当前少了比较,得出最大值的一步。

  • //那么要怎么写呢?

  • //在可以得到子序列的情况下,对比一下不同子序列的大小,即可得出最大值。

  • //然后返回最大值

  • //下一步,还是剪枝,用上面的那个思想的话,“对每一个数字,记录使用该数字时的最大子序列长度。若下一次长度小于该长度,就可以不必再计算了”

  • //这一步,该放在哪里?目前可以得知,应该是在计算用新的初始值计算的时候,进行判断。

  • //储存的是到达指定数字时的最大子序列,所以怎么找到到达该数字时的子序列,然后进行对比?

  • //按原本的思路的话,是1+1+1...一直加到结束,然后总结,得出初始值的最大子序列

  • //根本得不到到该数字时的子序列,得到的只会是最大子序列,所以得改变思路。

  • //新思路,递推。

  • //设置一个 n 值,用于保存到达该初始值时的最大子序列,

  • //n 为全局变量,每次循环都会调用并+1,那么在函数进行时,n的值便是当前数字的子序列

  • //对比该数字的最大子序列,就可以进行剪枝了

  • //需要注意的是,为了避免 n 的值只增不减,记得做回溯操作,在循环调用函数的时候,调用完了,就给n-1

  • //其实我想做的是,仅递推的,但又想不出来怎么做,只好接着递归,然后用n值来剪枝了

  • //运算函数这就算写好了,那下一步就是主函数了

  • //主函数需要有的内容是,对每个数字作为初始值来运算,找到最大的那个

  • //那用循环就行了吧?应该是,我试试。

  • //奇了怪了,明明特意做了剪枝操作,却还是超出时间限制。

  • //那一是剪枝做的不够好,二是这剪枝有问题,做了等于没做。

  • //先假设是第二个问题,剪枝有问题,做了等于白做,找下bug看看

  • //首先删去剪枝,对比一下结果有没有问题

  • //啧,剪枝没问题,能正常使用,那就是第一个问题了,效率不够好,还得找更优解

代码

点击查看代码
int lengthOfLIS(int* nums, int numsSize){


int jj,n=1,max=0,localmax[3000]={0};
//jj的作用看下面的循环,n用于剪枝,max用于存储最大值,localmax用于存储指定数字的最大子序列
int yunsuan(int p,int m)//p是初始值,m是p在数组中的下标
{
    if(n>localmax[m])   //若n>指定下标的最大值,使得指定下标的最大值为n,否则结束函数.
    {
        localmax[m]=n;
    }
    else
    {
        return 0;
    }
    int x=0,da=0;
    for(int i=m+1;i<numsSize;i++)	//从当前下标+1开始,对每个数字进行计算
    {
        if(nums[i]>p)	//若该数字大于原数值
        {
            n++;	//储存n值,用于剪枝
            x=1+yunsuan(nums[i],i);	//则递归运算,当前子序列等于1+剩余的子序列
            if(x>da)	//若计算结果 x 为更大值
            {
                da=x;	//则对最大值 da 赋值计算结果 x
            }
            n--;	//回溯n值
        }
    }
    return da;	//返回最大值(最大子序列)
}
for(int i=0;i<numsSize;i++)	//把每个数字当做初始值,进行运算
{
    jj=1+yunsuan(nums[i],i);	//用jj储存运算结果
    if(jj>max)	//比较运算结果 jj 和最大值 max
    {
        max=jj;
    }
}
return max;	//最后输出 x 值。就算做完了。
}

俺的一些话

其实这个做法过不过得看运气,我第一次提交超时了,第二次提交却过了
哎嘿嘿,真幸运。(~ ̄▽ ̄)~
过两天我再做个更优解试试。ヾ(o´∀`o)ノ
现在就这样将就着用吧,啦啦啦~


哦对了,这题我是在力扣上做的,所以详细的过程或许会有点偏差,不过思路应该都是通用的啦。就这样了,拜了个拜~

标签:剪枝,数字,int,递增,初始值,最大值,序列,最长
From: https://www.cnblogs.com/aduiduidui/p/17013724.html

相关文章