Skip to content

📚 28.最长递增子序列

💻 代码实现

typescript
// @ts-nocheck
/**
 * @url https://leetcode.cn/problems/longest-increasing-subsequence/description/
 */
// function lengthOfLIS(nums: number[]): number {}

// notice:找出所有的递增子序列,回溯法暴力搜索
// TODO:思考一下暴力搜索

// function lengthOfLIS(nums: number[]): number {
//     const res: number[][] = []
//     const dfs = (path: number[], startIndex: number) => {
//         const set: Set<number> = new Set()

//         if (path[path.length - 1] <= path[path.length - 2]) {
//             path.pop()
//             res.push(path.concat())
//             return
//         }
//         if (startIndex >= nums.length) {
//             res.push(path.concat())
//             return
//         }
//         for (let i = startIndex; i < nums.length; i++) {
//             if (set.has(nums[i])) {
//                 continue
//             }

//             path.push(nums[i])
//             set.add(nums[i])
//             dfs(path.concat(), i + 1)
//             path.pop()
//         }
//     }
//     const findMax = (arr: number[][]) => {
//         let max = Number.MIN_SAFE_INTEGER
//         arr.forEach((_v) => {
//             max = Math.max(_v.length, max)
//         })
//         return max
//     }
//     dfs([], 0)

//     return findMax(res)
// }

// console.log(lengthOfLIS([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]))

// TODO:动态规划
// dp[i]表示到达第i个位置所能获得的最长递增子序列
// dp[i] = dp[j]+1 nums[i] > nums[j]
function lengthOfLIS(nums: number[]): number {
  const dp = new Array(nums.length).fill(1); // 初始化的时候注意一点
  for (let i = 0; i < nums.length; i++) {
    for (let j = 0; j < i; j++) {
      if (nums[i] > nums[j]) {
        dp[i] = Math.max(dp[j] + 1, dp[i]);
      }
    }
  }
  return Math.max(...dp);
}
// console.log(lengthOfLIS([1, 3, 6, 7, 9, 4, 10, 5, 6]))


// ps: 如果要知道子序列是什么的做法
/**
 * @param {number[]} nums
 * @return {number[]}
 */
var findLIS = function(nums) {
  if (!nums.length) return [];
  
  // dp[i] 表示以 nums[i] 结尾的最长递增子序列长度
  const dp = new Array(nums.length).fill(1);
  // prev[i] 记录 dp[i] 从哪个位置 j 转移过来
  const prev = new Array(nums.length).fill(-1);
  
  // 动态规划计算 LIS 长度和前驱
  for (let i = 1; i < nums.length; i++) {
      for (let j = 0; j < i; j++) {
          if (nums[i] > nums[j] && dp[j] + 1 > dp[i]) {
              dp[i] = dp[j] + 1;
              prev[i] = j;
          }
      }
  }
  
  // 找到 dp 中的最大值及其索引
  let maxLen = 1;
  let endIndex = 0;
  for (let i = 0; i < dp.length; i++) {
      if (dp[i] > maxLen) {
          maxLen = dp[i];
          endIndex = i;
      }
  }
  
  // 回溯构造子序列
  const result = [];
  while (endIndex !== -1) {
      result.push(nums[endIndex]);
      endIndex = prev[endIndex];
  }
  
  // 反转结果,因为回溯是从后向前
  return result.reverse();
};

Released under the MIT License.