【每日一题】最长递增子序列,给定一个无序的整数数组,找到其中最长上升子序列的长度。

299 阅读3分钟

题目:最长递增子序列

给定一个无序的整数数组,找到其中最长上升子序列的长度。

例如,对于数组 [10, 9, 2, 5, 3, 7, 101, 18],最长递增子序列是 [2, 3, 7, 18],长度为 4。

请实现一个函数 lengthOfLIS,该函数接受一个整数数组作为参数,返回最长上升子序列的长度。

要求:

  1. 使用动态规划或其他适当的算法实现。
  2. 提供算法的时间复杂度和空间复杂度分析。
/**
 * @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 函数。

74d801682d4f401e9f3e90944bd4b616_3.png

方法一:动态规划

// 定义一个函数,接收一个整数数组作为参数,返回最长递增子序列的长度
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

上述代码使用贪心算法结合二分查找的思想,在遍历数组的过程中,维护一个递增子序列的尾部元素,不断更新这个递增子序列,最终返回递增子序列的长度。

结语:答案如有误,欢迎纠正指出,也可以在评论区写出您的见解,共同学习,每天进步一点点。

扫码_搜索联合传播样式-白色版.png