栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

LeetCode

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

LeetCode

文章目录
    • 1.线性动态规划
    • 2.例题练习
    • 最长递增子序列
    • 最长递增子序列的个数

1.线性动态规划

线性动态规划的特点是:状态推导按照i从小到大进行推导。
大规模的解答依靠小规模的解答。

解决动态规划问题大体上分为:

  • 问题的Base Case情况(最简单的情况)
  • 问题的状态有哪些
  • 什么选择问题的状态可能会改变
  • 如何定义dp数组表达状态和选择(状态转移)

线性动态规划状态定义一般为:

dp[n]:0~n符合题干的答案

状态转移一般有两种情况:

1. 依赖比 i 小的 O(1) 个子问题

dp[n] = f(dp[n-1], ..., dp[0]);
其中f一般为最大值和最小值函数。具体情况具体分析

2. 依赖比 i 小的 O(n) 个子问题
此时dp[n] 与此前的更小规模的所有子问题 dp[n - 1], dp[n - 2], …, dp[1] 都可能有关系

for(int i=1;i
	for(int j=1;j
		dp[i]=f(dp[i],f(dp[j]))
	}
}
其中f一般为最大值和最小值函数。具体情况具体分析

线性动态规划分为:单串,双串,矩阵问题等,这里先练习单串最经典的LIS问题。

2.例题练习 最长递增子序列

LeetCode原题链接

思路:输入是一个单串,首先思考单串问题中设计状态

  1. dp[i]数组定义:代表数组下标为i时最长子序列。包括数组下标为i的元素。
  2. 初始状态:当i=0时,数组只有一个元素,所以dp[0]=1。
  3. 每次选择是将数组的下标+1,代表检测过这个元素了。这个选择会影响最长子序列。
  4. 状态转化:因为dp[i]是数组下标为i时最长子序列,但不一定dp[i-1]一定小于dp[i]。所以这个状态转化为dp[i]=max(dp[i],(dp[0]…dp[i-1])+1)。
  5. 需要注意,更新dp数组的时机,当num[0]…num[i-1]之间有元素
  6. 最后的值是dp数组中最大的值,所以需要记录最大值作为返回值。

eg:
nums[j] 此时的dp[i]=max(dp[i],dp[j]+1);
需要遍历0~i-1次dp数组才可以判断dp[i]的值。
这个状态转移是第二类。依赖比 i 小的 O(n) 个子问题

class Solution {
public:
    int lengthOfLIS(vector& nums) {
        //dp[i]代表数组下标为i时最长子序列
        vectordp(nums.size(),1);
        dp[0]=1;
        int ret=1;
        for(int i=1;i
            for(int j=0;j
                //因为dp[i]最大值不一定是最后值,所以每次都需要遍历一遍dp数组找最大值
                if(nums[j]
                    dp[i]=max(dp[j]+1,dp[i]);
                }
            }
            ret=max(ret,dp[i]);
        }
        return ret;
    }
};
最长递增子序列的个数

LeetCode原题链接

这个题的思路与上题相同,但是需要返回最长递增的子序列个数。

首先,我们是按照递增的方式找的子序列,所以数列一定是递增的。

我们定义一个数组count,count[i]代表nums[i]元素之前的递增序列长度有多少个。
最后答案为count数组中长度是最长子序列的所有数组元素和。

int longest;//最长递增子序列
int ans;//最后答案
for(int i=0;i
	if (dp[i] == longest) {
    	ans += counts[i];
    }
}

之所以这么设,是因为最长递增子序列可能在dp数组的任何一个位置。

其次在一问中我们可以知道

当dp[i]>dp[j]需要更新dp数组
dp[i]=max(dp[i],(dp[0]…dp[i-1])+1)

for(int i=1;i
    for(int j=0;j
        //因为dp[i]最大值不一定是最后值,所以每次都需要遍历一遍dp数组找最大值
        if(nums[j]
           //dp[i]=max(dp[j]+1,dp[i]);
           if(dp[j]>=dp[i]){
          	  dp[i]=dp[j]+1	;
          	  count[i]=count[j];//最长递增子序列发生改变,此时count[i]为最长递增子序列,其值和发生改变的上一个位置相同。
           }
           else if(dp[j] + 1 == dp[i]){
           	  //最长递增子序列长度没变化,但是序列发生变化,有count[j] 个额外的序列
           	  count[i]+=count[j];
           }
        }
    }
    ret=max(ret,dp[i]);
}
  • 如果这些序列比 length[i] 长,那么我们就知道我们有count[j] 个长度为 length 的序列。
  • length[j] + 1 = length[i]说明在某个最长递增序列中,num[j]正好是num[i]的前一个元素。那么num[j]所对应的count[j]应该要累加到num[i]所对应的count[i]上
class Solution {
public:
    int findNumberOfLIS(vector& nums) {
        int size=nums.size();
        if(size==0||size==1){
            return size;
        }
        vectordp(size,1);
        vectorcount(size,1);
        dp[0]=1;
        count[0]=1;
        int maxlen=1;
        for(int i=0;i
            for(int j=0;j
                if(nums[i]>nums[j]){
                    //dp[i]=max(dp[j]+1,dp[i]);
                    if(dp[j]+1==dp[i]){
                        count[i]+=count[j];
                    }
                    else if(dp[j]+1>=dp[i]){
                        count[i]=count[j];
                        dp[i]=dp[j]+1;                        
                    }
                }
            }
            maxlen=max(maxlen,dp[i]);
        }
        int ans=0;
        for(int i=0;i
            if(dp[i]==maxlen){
                ans+=count[i];
            }
        }
        return ans;
    }
};
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/847309.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号