题目:最长递增子序列
给定一个无序的整数数组,找到其中最长上升子序列的长度。
例如,对于数组 [10, 9, 2, 5, 3, 7, 101, 18],最长递增子序列是 [2, 3, 7, 18],长度为 4。
请实现一个函数 lengthOfLIS,该函数接受一个整数数组作为参数,返回最长上升子序列的长度。
要求:
- 使用动态规划或其他适当的算法实现。
- 提供算法的时间复杂度和空间复杂度分析。
/**
* @param {number[]} nums
* @return {number}
*/
function lengthOfLIS(nums) {
// 你的代码实现
}
// 示例
const nums = [10, 9, 2, 5, 3, 7, 101, 18];
const result = lengthOfLIS(nums);
console.log(result); // 输出 4
请编写一个满足以上要求的 lengthOfLIS 函数。
方法一:动态规划
// 定义一个函数,接收一个整数数组作为参数,返回最长递增子序列的长度
function lengthOfLIS(nums) {
// 如果数组为空,返回 0,表示最长递增子序列的长度为 0
if (nums.length === 0) {
return 0;
}
// 创建一个数组 dp,用于存储以每个元素为结尾的最长递增子序列的长度,初始值全部为 1
const dp = new Array(nums.length).fill(1);
// 遍历数组,计算以每个元素为结尾的最长递增子序列长度
for (let i = 1; i < nums.length; i++) {
// 再次遍历之前的元素
for (let j = 0; j < i; j++) {
// 如果当前元素 nums[i] 大于之前的某个元素 nums[j]
if (nums[i] > nums[j]) {
// 更新以当前元素为结尾的最长递增子序列长度
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
// 返回 dp 数组中的最大值,即为整个数组的最长递增子序列长度
return Math.max(...dp);
}
// 示例
const nums = [10, 9, 2, 5, 3, 7, 101, 18];
const result = lengthOfLIS(nums);
console.log(result); // 输出 4
方法二:贪心算法 + 二分查找
// 定义一个函数,接收一个整数数组作为参数,返回最长递增子序列的长度
function lengthOfLIS(nums) {
// 如果数组为空,返回 0,表示最长递增子序列的长度为 0
if (nums.length === 0) {
return 0;
}
// 创建一个数组 tails,用于存储递增子序列的尾部元素
const tails = [nums[0]];
// 遍历数组,更新递增子序列的尾部元素
for (let i = 1; i < nums.length; i++) {
// 如果当前元素 nums[i] 大于递增子序列的尾部元素
if (nums[i] > tails[tails.length - 1]) {
// 将当前元素加入递增子序列
tails.push(nums[i]);
} else {
// 使用二分查找找到递增子序列中第一个大于等于当前元素的位置
let left = 0;
let right = tails.length - 1;
while (left < right) {
const mid = Math.floor((left + right) / 2);
if (tails[mid] < nums[i]) {
left = mid + 1;
} else {
right = mid;
}
}
// 更新递增子序列中第一个大于等于当前元素的位置的值为当前元素
tails[left] = nums[i];
}
}
// 返回递增子序列的长度,即为 tails 数组的长度
return tails.length;
}
// 示例
const nums = [10, 9, 2, 5, 3, 7, 101, 18];
const result = lengthOfLIS(nums);
console.log(result); // 输出 4
上述代码使用贪心算法结合二分查找的思想,在遍历数组的过程中,维护一个递增子序列的尾部元素,不断更新这个递增子序列,最终返回递增子序列的长度。
结语:答案如有误,欢迎纠正指出,也可以在评论区写出您的见解,共同学习,每天进步一点点。