最长递增子序列
300. 最长递增子序列 - 力扣(LeetCode)
dp[i]为到当前位置i为止的最长递增子序列的长度,所以dp[nums.size()-1]并不一定是整个数组的最长递增子序列的长度。这里需要注意,但这个dp[i]怎么来的,我确实没想到。。。
由于是到当前位置i为止的最长递增子序列的长度,所以当当前的nums[i]大于先前元素nums[j],
dp[i] = max(dp[i],dp[j] + 1)。
dp[i] = 1,当全乱序的情况下,最长递增子序列长度为1,也是初始值。
从前向后遍历,嵌套循环遍历,时间复杂度为O(n^2)。
最后返回的是dp[i]中元素的最大值。
class Solution {
public:int lengthOfLIS(vector<int>& nums) {if (nums.size() == 0) // 如果数组为空返回0return 0; vector<int> dp(nums.size(), 1); // dp[i]将存储以nums[i]结尾的最长递增子序列的长度for (int i = 1; i < nums.size(); i++) { // 遍历nums数组,从第二个元素开始for (int j = 0; j < i; j++) { // 遍历i之前的所有元素if (nums[i] > nums[j]) // 如果当前元素大于j位置的元素dp[i] = max(dp[i], dp[j] + 1); // 更新dp[i]为dp[i]和dp[j]+1中的较大值}}return *max_element(dp.begin(), dp.end()); // 使用*max_element函数找到dp数组中的最大值并返回// 这个最大值就是最长递增子序列的长度}
};
此处注意max_element返回的是最大值的迭代器,所以加*号解引用得到值的大小。
算法的时间复杂度为O(n^2),空间复杂度为O(n)。
最长连续递增序列
674. 最长连续递增序列 - 力扣(LeetCode)
此题相比上题简单许多,贪心也很好做,存储一个计数指示,当前元素大于先前元素,指示++,否则,指示为1,最后返回最大的计数值。
用dp思路的话。
dp[i]表示以先前元素到i的连续递增序列的长度,注意这里不考虑最长的情况
如果nums[i] > nums[i-1],dp[i] = dp[i-1]+1,否则dp[i] = 1。
将所有元素初始化为1。
从前向后遍历。
最终返回dp数组的最大值
class Solution {
public:int findLengthOfLCIS(vector<int>& nums) { // 类的一个公有成员函数,用于计算最长连续递增子序列的长度vector<int> dp(nums.size(), 1); // 创建一个动态数组dp,大小与输入的nums相同,初始化所有值为1// dp[i]将存储以nums[i]结尾的最长连续递增子序列的长度int maxlength = 1; // 初始化最长递增子序列的长度为1for (int i = 1; i < nums.size(); i++) { // 遍历nums数组,从第二个元素开始if (nums[i] > nums[i - 1]) // 如果当前元素大于前一个元素dp[i] = dp[i - 1] + 1; // 则dp[i]等于dp[i-1]加1,表示递增子序列长度增加maxlength = max(dp[i], maxlength); // 更新最长递增子序列的长度}return maxlength; // 返回计算得到的最长连续递增子序列的长度}
};
算法的时间复杂度为O(n),空间复杂度为O(n)。
最长重复子数组
. - 力扣(LeetCode)
具体思路看下面代码随想录的网址链接。
代码随想录 (programmercarl.com)
dp[i][j]表示以nums1[i-1]和nums2[j-1]为结尾的两个数组的最长公共连续子数组的长度。
当nums1[i-1] == nums[j-1]时,dp[i][j] = dp[i-1][j-1] + 1。
dp[0][0] = 0
遍历从i = 1开始到nums1.size(),j从1到nums2.size(),嵌套循环。这里从1开始的原因在于我们需要比较nums[i-1]和nums[j-1],而其实dp[0][0]是没有意义的,但可以用来推导后续的dp值。
最后返回dp数组中最大值即为两个数组的最长公共连续子数组的长度。
class Solution {
public:int findLength(vector<int>& nums1, vector<int>& nums2) {// 创建一个二维动态数组dp,用于存储子问题的解// dp[i][j]表示以nums1[i-1]和nums2[j-1]结尾的最长公共连续子数组的长度vector<vector<int>> dp(nums1.size()+1, vector<int>(nums2.size()+1, 0));int result = 0; // 用于存储最终的最长公共连续子数组的长度// 遍历数组nums1和nums2for(int i = 1; i <= nums1.size(); i++){ // 注意i从1开始,i=0没有实质意义for(int j = 1; j <= nums2.size(); j++){ // 同理j也从1开始// 如果当前两个数字相等if(nums1[i-1] == nums2[j-1]){// 更新dp[i][j]为dp[i-1][j-1]加1// 这意味着以nums1[i-1]和nums2[j-1]结尾的最长公共连续子数组的长度// 等于以nums1[i-2]和nums2[j-2]结尾的最长公共连续子数组的长度加1dp[i][j] = dp[i-1][j-1] + 1;}// 如果以nums1[i-1]和nums2[j-1]结尾的最长公共连续子数组的长度大于当前结果// 更新结果为dp[i][j]if(dp[i][j] > result)result = dp[i][j];}}// 返回最终的最长公共连续子数组的长度return result;}
};
时间复杂度是O(nm),其中n和m分别是两个数组的长度。空间复杂度也是O(nm),因为需要一个二维数组来存储所有子问题的解。