[Java 算法] 动态规划(4)

练习一 : 最长递增子序列

300. 最长递增子序列 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int lengthOfLIS(int[] nums) {
        int n = nums.length;
        int[] dp = new int[n];
        // 初始化:每个元素至少是长度为1的子序列
        Arrays.fill(dp, 1);
        int maxLen = 1;

        for (int i = 1; i < n; i++) {
            for (int j = 0; j < i; j++) {
                // 如果nums[i]可以接在nums[j]后面
                if (nums[i] > nums[j]) {
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
            maxLen = Math.max(maxLen, dp[i]);
        }
        return maxLen;
    }
}

算法原理

  1. DP 状态定义 : dp[i]:以 nums [i] 这个数字结尾的最长递增子序列长度。

  2. 初始化 : dp[i] = 1因为每个数字自己单独就是一个长度为 1 的递增子序列。

  3. 对于每个数 nums[i],看它前面所有的数 nums[j]只要 nums[j] < nums[i],说明 nums[i] 可以接在以 j 结尾的序列后面长度就变成:dp[j] + 1

练习二 : 摆动序列

376. 摆动序列 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int wiggleMaxLength(int[] nums) {
        int n = nums.length;
        int[] f = new int[n];
        int[] g = new int[n];
        int ret = 1;
        for(int i = 0;i<n;i++) f[i] = g[i] = 1;
        for(int i = 1;i<n;i++){
            for(int j = i-1;j>=0;j--){
                if(nums[j]<nums[i]){
                    f[i] = Math.max(f[i],g[j]+1);
                }
                if(nums[j]>nums[i]){
                    g[i] = Math.max(g[i],f[j]+1);
                }
                ret = Math.max(Math.max(f[i],g[i]),ret);
            }
        }
        return ret;
    }
}

算法原理

  1. 状态定义(你用了两个 dp 数组,非常标准)
    f[i]:以 nums [i] 结尾,且最后一步是上升(nums [i] > 前一个数)的最长摆动序列长度
    g[i]:以 nums [i] 结尾,且最后一步是下降(nums [i] < 前一个数)的最长摆动序列长度
  2. 初始化 f[i] = g[i] = 1
    每个元素自己就是一个长度为 1 的摆动序列。
  3. 状态转移(你写得完全正确!)
    (1)当 nums [j] < nums [i] → 上升 说明i 可以接在 j 的下降序列后面 f[i] = max(f[i], g[j] + 1)
    (2)当 nums [j] > nums [i] → 下降 说明i 可以接在 j 的上升序列后面g[i] = max(g[i], f[j] + 1)
    摆动序列要求:上升 ↔ 下降 交替
    所以:
    想上升,必须接在下降结尾后面
    想下降,必须接在上升结尾后面
  4. 答案
    遍历过程中 f[i] 和 g[i] 的最大值

练习三 : 最长递增子序列的个数

673. 最长递增子序列的个数 - 力扣(LeetCode)

.

java 复制代码
class Solution {
    public int findNumberOfLIS(int[] nums) {
        int n = nums.length;
        int[] len = new int[n]; // 以i结尾的最长递增子序列长度
        int[] cnt = new int[n]; // 以i结尾的最长递增子序列的个数
        // 初始化
        for (int i = 0; i < n; i++) {
            len[i] = 1;
            cnt[i] = 1;
        }

        int maxLen = 1; // 全局最长长度
        // 填dp表
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < i; j++) {
                if (nums[j] < nums[i]) { // 严格递增
                    if (len[j] + 1 > len[i]) {
                        // 找到更长的序列,更新长度和计数
                        len[i] = len[j] + 1;
                        cnt[i] = cnt[j];
                    } else if (len[j] + 1 == len[i]) {
                        // 长度相同,累加计数
                        cnt[i] += cnt[j];
                    }
                }
            }
            // 更新全局最长长度
            maxLen = Math.max(maxLen, len[i]);
        }

        // 统计所有长度等于maxLen的个数之和
        int res = 0;
        for (int i = 0; i < n; i++) {
            if (len[i] == maxLen) {
                res += cnt[i];
            }
        }
        return res;
    }
}

算法原理

  1. 状态定义

len[i]:以 nums[i] 结尾的最长递增子序列的长度

cnt[i]:以 nums[i] 结尾的、长度为 len[i] 的最长递增子序列的个数

  1. 初始化

len[i] = 1:每个元素自身是长度为 1 的子序列

cnt[i] = 1:每个元素自身对应 1 个长度为 1 的子序列

  1. 状态转移

遍历每个 i,枚举所有 j < i:

若 nums[j] < nums[i](满足严格递增):

若 len[j] + 1 > len[i]:说明找到了更长的子序列,更新 len[i] = len[j] + 1,同时 cnt[i] = cnt[j](个数继承自 j)

若 len[j] + 1 == len[i]:说明找到了长度相同的新子序列,累加计数 cnt[i] += cnt[j]

若 nums[j] >= nums[i]:不满足严格递增,跳过

  1. 最终结果

先遍历 len 数组,找到全局最长长度 maxLen

再遍历所有 i,累加所有 len[i] == maxLen 的 cnt[i],即为答案

相关推荐
Old Uncle Tom23 分钟前
OpenClaw 记忆系统 -- 记忆预加载
java·数据结构·算法·agent
会编程的土豆33 分钟前
洛谷题单入门1 顺序结构
数据结构·算法·golang
生信碱移35 分钟前
PACells:这个方法可以鉴定疾病/预后相关的重要细胞亚群,作者提供的代码流程可以学习起来了,甚至兼容转录组与 ATAC 两种数据类型!
人工智能·学习·算法·机器学习·数据挖掘·数据分析·r语言
智者知已应修善业1 小时前
【51单片机中的打飞机设计】2023-8-25
c++·经验分享·笔记·算法·51单片机
圣保罗的大教堂2 小时前
leetcode 1855. 下标对中的最大距离 中等
leetcode
智者知已应修善业3 小时前
【51单片机按键调节占空比3位数码管显示】2023-8-24
c++·经验分享·笔记·算法·51单片机
JasmineX-14 小时前
数据结构(笔记)——双向链表
c语言·数据结构·笔记·链表
.5484 小时前
## Sorting(排序算法)
python·算法·排序算法
wuweijianlove4 小时前
算法的平均复杂度建模与性能回归分析的技术7
算法·数据挖掘·回归
子琦啊4 小时前
【算法复习】字符串 | 两个底层直觉,吃透高频题
linux·运维·算法