leetcode 子序列问题

 


一般来说,这类问题都是让你求一个最长子序列,因为最短子序列就是一个字符嘛,没啥可问的。一旦涉及到子序列和最值,那几乎可以肯定,考察的是动态规划技巧,时间复杂度一般都是 O(n^2)。

原因很简单,你想想一个字符串,它的子序列有多少种可能?起码是指数级的吧,这种情况下,不用动态规划技巧,还想怎么着?

既然要用动态规划,那就要定义 dp 数组,找状态转移关系。我们说的两种思路模板,就是 dp 数组的定义思路。不同的问题可能需要不同的 dp 数组定义来解决。
涉及两个字符串/数组时(比如最长公共子序列),dp 数组的含义如下:

在子数组 arr1[0..i] 和子数组 arr2[0..j] 中,我们要求的子序列(最长公共子序列)长度为 dp[i][j]。

2.2 只涉及一个字符串/数组时(比如本文要讲的最长回文子序列),dp 数组的含义如下:

在子数组 array[i..j] 中,我们要求的子序列(最长回文子序列)的长度为 dp[i][j]

1. 最长回文子序列

给定一个字符串 s ,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s 的最大长度为 1000 。

示例 1:
输入:

"bbbab"
输出:
4

class Solution {
    public int longestPalindromeSubseq(String s) {
        int n = s.length();
        int[][] dp = new int[n][n];
        for (int i = 0; i < n; i++)
            dp[i][i] = 1;
        for (int i = n - 2; i >= 0; i--) {
            for (int j = i + 1; j < n; j++) {
                if (s.charAt(i) == s.charAt(j))
                    dp[i][j] = dp[i + 1][j - 1] + 2;
                else
                    dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
            }
        }
        return dp[0][n-1];
    }
}

2. 所有递增子序列(491)

给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。

示例:

输入: [4, 6, 7, 7]
输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]
说明:

给定数组的长度不会超过15。
数组中的整数范围是 [-100,100]。
给定数组中可能包含重复数字,相等的数字应该被视为递增的一种情况。

//直接回溯
class Solution {
    Set<List<Integer>> res;
    int[] nums;
    int n;
    public List<List<Integer>> findSubsequences(int[] nums) {
        this.nums = nums;
        this.n = n;
        res = new HashSet<>();
        helper(new ArrayList<Integer>(), 0);
        return new ArrayList(res);
    }

    void helper(List<Integer> cur, int start) {
        if (cur.size() >= 2) {
            res.add(new ArrayList<Integer>(cur));
        }
        for (int i = start; i < nums.length; i ++) {
            if (cur.size() == 0 || cur.get(cur.size() - 1) <= nums[i]) {
                cur.add(nums[i]);
                helper(cur, i + 1);
                cur.remove(cur.size() - 1);
            }
        }
    }
}


//时间优化
//https://leetcode-cn.com/problems/increasing-subsequences/solution/dfs-ctong-su-yi-dong-de-jie-ti-si-lu-by-guanzhanyi/


3. 最长上升子序列(300)

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

示例:

输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:

可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。

class Solution {
    public int lengthOfLIS(int[] nums) {
        int n = nums.length;
        if(n == 0 || n == 1) return n;
        //dp[i]表示包含nums[i]的最长子串
        int[] dp = new int[n];
        dp[0] = 1;
        for(int i = 0;i < n;i++){
            int max = 1;
            for(int j = 0;j < i;j++){
                if(nums[i] > nums[j]){
                    max = Math.max(max,dp[j] + 1);
                }
            }
            dp[i] = max;
        }
        Arrays.sort(dp);
        return dp[n-1];
    }
}

4. 最长上升子序列的个数(673)

//再维护一个数组,以counter[i]表示包含nums[i]的最长子串的个数

class Solution {
    public int findNumberOfLIS(int[] nums) {
            if (nums == null || nums.length == 0) return 0;
            int n = nums.length;
            int[] dp = new int[n];
            int[] counter = new int[n];
            Arrays.fill(dp, 1);
            Arrays.fill(counter, 1);
            int max = 0;
            for(int i = 0; i < n; i++) {
                for (int j = 0; j < i; j++) {
                    if (nums[i] > nums[j]) {
                        if (dp[j] + 1 > dp[i]) {
                            dp[i] = Math.max(dp[i], dp[j] + 1);
                            counter[i] = counter[j];
                        } else if (dp[j] + 1 == dp[i]) {
                            counter[i] += counter[j];
                        }
                    }
                }
                max = Math.max(max, dp[i]);
            }
            int res = 0;
            for (int i = 0; i < n; i++) {
                if (dp[i] == max) res += counter[i];
            }
            return res;
        }
}
posted @   aixueforever  阅读(225)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示