面试经典算法题77-最长递增子序列
LeetCode.300
问题描述
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例 1:
c++
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。示例 2:
c++
输入:nums = [0,1,0,3,2,3]
输出:4示例 3:
c++
输入:nums = [7,7,7,7,7,7,7]
输出:1思路
- 状态定义:使用一个数组
dp,其中dp[i]表示以nums[i]结尾的最长严格递增子序列的长度。 - 状态转移方程:对于每个
i,检查在它之前的每个元素j(即0 ≤ j < i),如果nums[i] > nums[j],则可以将nums[i]添加到以nums[j]结尾的子序列之后。此时,dp[i] = max(dp[i], dp[j] + 1)。 - 初始状态:每个元素单独作为子序列时长度为1,因此
dp数组初始化为1。 - 最终结果是
dp数组中的最大值,即最长严格递增子序列的长度。
参考代码
C++
c++
#include <iostream>
#include <vector>
#include <algorithm> // 为了使用 max 函数
using namespace std;
int lengthOfLIS(vector<int>& nums) {
if (nums.empty()) return 0;
// 定义 dp 数组,初始长度为 nums 的长度,每个元素初始化为 1
vector<int> dp(nums.size(), 1);
// 遍历数组的每个元素
for (int i = 1; i < nums.size(); ++i) {
// 遍历当前元素之前的每个元素
for (int j = 0; j < i; ++j) {
// 如果当前元素大于之前的元素
if (nums[i] > nums[j]) {
// 更新 dp[i],表示以 nums[i] 结尾的最长递增子序列长度
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
// 返回 dp 数组中的最大值,即最长递增子序列的长度
return *max_element(dp.begin(), dp.end());
}
int main() {
vector<int> nums1 = {10, 9, 2, 5, 3, 7, 101, 18};
cout << "输入: [10, 9, 2, 5, 3, 7, 101, 18]" << endl;
cout << "输出: " << lengthOfLIS(nums1) << endl; // 输出: 4
vector<int> nums2 = {0, 1, 0, 3, 2, 3};
cout << "输入: [0, 1, 0, 3, 2, 3]" << endl;
cout << "输出: " << lengthOfLIS(nums2) << endl; // 输出: 4
vector<int> nums3 = {7, 7, 7, 7, 7, 7, 7};
cout << "输入: [7, 7, 7, 7, 7, 7, 7]" << endl;
cout << "输出: " << lengthOfLIS(nums3) << endl; // 输出: 1
return 0;
}Java
java
import java.util.Arrays;
public class LongestIncreasingSubsequence {
// 方法:计算最长递增子序列的长度
public static int lengthOfLIS(int[] nums) {
if (nums == null || nums.length == 0) return 0;
// 初始化 dp 数组,每个位置的初始值为 1
int[] dp = new int[nums.length];
Arrays.fill(dp, 1);
// 遍历数组中的每个元素
for (int i = 1; i < nums.length; i++) {
// 遍历当前元素之前的每个元素
for (int j = 0; j < i; j++) {
// 如果当前元素大于之前的元素
if (nums[i] > nums[j]) {
// 更新 dp[i],表示以 nums[i] 结尾的最长递增子序列长度
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
// 返回 dp 数组中的最大值,即最长递增子序列的长度
int maxLength = 0;
for (int length : dp) {
maxLength = Math.max(maxLength, length);
}
return maxLength;
}
public static void main(String[] args) {
int[] nums1 = {10, 9, 2, 5, 3, 7, 101, 18};
System.out.println("输入: [10, 9, 2, 5, 3, 7, 101, 18]");
System.out.println("输出: " + lengthOfLIS(nums1)); // 输出: 4
int[] nums2 = {0, 1, 0, 3, 2, 3};
System.out.println("输入: [0, 1, 0, 3, 2, 3]");
System.out.println("输出: " + lengthOfLIS(nums2)); // 输出: 4
int[] nums3 = {7, 7, 7, 7, 7, 7, 7};
System.out.println("输入: [7, 7, 7, 7, 7, 7, 7]");
System.out.println("输出: " + lengthOfLIS(nums3)); // 输出: 1
}
}Python
python
from typing import List
def lengthOfLIS(nums: List[int]) -> int:
if not nums:
return 0
# 初始化 dp 数组,每个位置的初始值为 1
dp = [1] * len(nums)
# 遍历数组中的每个元素
for i in range(1, len(nums)):
# 遍历当前元素之前的每个元素
for j in range(i):
# 如果当前元素大于之前的元素
if nums[i] > nums[j]:
# 更新 dp[i],表示以 nums[i] 结尾的最长递增子序列长度
dp[i] = max(dp[i], dp[j] + 1)
# 返回 dp 数组中的最大值,即最长递增子序列的长度
return max(dp)
if __name__ == "__main__":
nums1 = [10, 9, 2, 5, 3, 7, 101, 18]
print("输入: [10, 9, 2, 5, 3, 7, 101, 18]")
print("输出:", lengthOfLIS(nums1)) # 输出: 4
nums2 = [0, 1, 0, 3, 2, 3]
print("输入: [0, 1, 0, 3, 2, 3]")
print("输出:", lengthOfLIS(nums2)) # 输出: 4
nums3 = [7, 7, 7, 7, 7, 7, 7]
print("输入: [7, 7, 7, 7, 7, 7, 7]")
print("输出:", lengthOfLIS(nums3)) # 输出: 1