刷题----最长上升子序列/最大上升子序列和

关于子序列的问题做个记录

一、最长上升子序列

        题目描述剥离,不管时搬箱子还是其他,一般来说,只要符合求后面的值比前面的大的序列长度基本上能套用

LIS解法(1)动态规划

        找到序列1 7 3 5 9 4 8最长上升子序列

        找到初始化条件&状态转移方程

        初始化:对于序列中的每个元素来说,它本身的长度都是1,这是个重要的初始化条件

        状态转移方程:对于i和j来说,假设索引i>j,序列为a的话。那么无非有两种情况,如果a[i] > a[j],那么序列的长度dp[j]+1 和dp[i]的值谁大的问题。即 maxLen = max(dp[i],dp[j]+1) ( a[i] > a[j]),注意此时只有a[i] 大于a[j]时才成立,也就是说当索引为i时,比较前 j个元素上升子序列+1 和 以i结尾时最长上升子序列谁大的问题

代码如下:

int boxMaxNum(vector<int> &numInfo)
{
    int allBoxNum = numInfo.size();
    int maxNum = 0;
    int *dp = new int[allBoxNum];
    //动态规划值初始化为1
    for (int m = 0; m < allBoxNum; m++) {
        dp[m] = 1;
    }
    //状态转移方程实现
    for (int i = 0; i < allBoxNum; i++) {
        for (int j = 0; j < i; j++) {
            if (numInfo[i] > numInfo[j]) {
                dp[i] = max(dp[j] + 1, dp[i]);
            }
        }
        maxNum = max(maxNum, dp[i]);
    }
    for (int k = 0; k < allBoxNum; k++) {
        cout << dp[k] << " ";
    }
    cout << endl;
    cout << "max num is:" << maxNum << endl;
    delete [] dp;
    
    return maxNum;
}

main函数:

int boxNum;
    cin >> boxNum;
    if (boxNum <= 0) {
        cout << 0 << endl;
    }
    vector<int> boxInfo;
    int numInfo;

    for (int i = 0; i < boxNum; i++) {
        cin >> numInfo;
        boxInfo.push_back(numInfo);
    }
    int maxNum = boxMaxNum(boxInfo);
    cout << maxNum << endl;

输出子序列和最大的上升子序列长度

二、最大上升子序列的和

       求最大上升子序列的和的问题  和  求最大上升子序列的长度 理论上时一致的  上面用dp[]来表示最大的长度,同样,也可以用dp[]来表示上升子序列的和,问题可以向下面转化

        初始状态: sum[i] = a[i],即每个值的位置的和为 其本身的值,初始值非常重要

        状态转移方程:当遍历到 i 位置时,需要不断比较  sum[i] 和 sum[j]+a[i]的大小,与上一题的思路完全一致,唯一变化的是初始值变成每个值自身。一个求的是最长的长度,一个是求累加的和,都用一个额外的数据结构来存储  中间的长度或者和 ,最后做下比较 。相当于说 定义的数据结构sumValue中存储的是  从前到后的之前计算的值

1 7 3 5 9 4 8---当遍历到5的时候,需要从1开始比较

j = 0:比较值sum[i] 和 sum[ j ] + numInfo[i]   -------max(5,6)------->6

j = 1:不用比较

j = 2: 比较 sum[ i ] 和sum[ j ] + numInfo[ i ]--------------max(6,   4  (sum[2]) + 5 (numInfo[3]))-----9

依次类推

转移方程:   max (  sum[ i ],   sum[ j ] + numInfo[ i ] )

                            当前的和的值     前一个和的值+当前值     

   代码:

int sumValue[1001];
int getMaxUpSum(vector<int> &numInfo)
{
    int maxSumValue = 0;
    int Len = numInfo.size();
    for (int k = 0; k < Len; k++) {
        sumValue[k] = numInfo[k];
    }
    for (int i = 1; i < Len; i++) {
        for (int j = 0; j < i; j++) {
            if (numInfo[i] > numInfo[j]) {
                sumValue[i] = max(sumValue[ j ] + numInfo[ i ], sumValue[ i ]);
            }
        }
    }
    for (int n = 0; n < Len; n++) {
        cout << sumValue[n] << " ";
    }
    return maxSumValue;
}

附上另外一个好的解释:https://www.nowcoder.com/questionTerminal/dcb97b18715141599b64dbdb8cdea3bd

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值