算法题目 动态规划

本文深入探讨动态规划算法,通过斐波那契数列、打家劫舍系列问题、信件错排、母牛生产、子序列问题等经典案例,解析动态规划的解题思路和技巧。内容涵盖了连续子序列、最长递增子序列、最长公共子序列等多个方面,旨在帮助读者掌握动态规划的核心思想和应用方法。
摘要由CSDN通过智能技术生成


斐波那契问题

爬楼梯

leetcode 70 爬楼梯(简单)
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.1 阶 + 1 阶
2.2 阶

示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。

  1. 1 阶 + 1 阶 + 1 阶
  2. 1 阶 + 2 阶
  3. 2 阶 + 1 阶

题解:

class Solution {
    public int climbStairs(int n) {
        //爬第k阶台阶,可以是从第k-1阶爬上来,也可以是从第k-2阶爬上来,所以,爬上第k阶楼梯的方法为爬上第k-1阶楼梯的方法+爬上第k-2阶楼梯的方法
        //动态规划实现
        if(n==1){
            return 1;
        }
        
        int[] dp = new int[n+1];  //dp[k]为爬上第k阶楼梯的方法数
        dp[1] = 1;
        dp[2] = 2;
        
        for(int k=3; k<=n; k++){
            dp[k] = dp[k-2]+dp[k-1];
        }     
        return dp[n];        
    }
}

打家劫舍

leetcode 198 打家劫舍(简单)
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:

输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。

示例 2:

输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。

题解:

class Solution {
    public int rob(int[] nums) {
        int n = nums.length;
        if(n == 0){
            return 0;
        }
        
        //定义状态,dp[k] 为考虑盗取第[0,k]号房子所取得的最大收益
        int[] dp = new int[n];
        dp[0] = nums[0];
     
        //状态转移方程,求解dp[k], dp[k] = max( nums[k]+dp[k-2], nums[k-1]+dp[k-3]... )
        //或者,状态转移方程,求解dp[k], dp[k] = max( nums[k]+dp[k-2], nums[k-1]+dp[k-3])
        for(int k=1; k<n; k++){
            dp[k] = 0;
            for(int i = k; i>=0; i--){
                dp[k] = Math.max((nums[i]+(i>=2 ? dp[i-2]:0)), dp[k]);
            }
        }

        return dp[n-1];        
    }
}

题解2:

class Solution {
    public int rob(int[] nums) {
        int n = nums.length;
        if(n==0){
            return 0;
        }
        
        int[] dp = new int[n];
        dp[0] = nums[0];
        
        for(int k=1; k<n; k++){
            dp[k] = Math.max(dp[k-1], nums[k]+(k-2>=0? dp[k-2]:0));
        }
        
        return dp[n-1];       
    }
}

环形区域内打家劫舍

leetcode 213 打家劫舍II(中等)
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:

输入: [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

示例 2:

输入: [1,2,3,1]
输出: 4
解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。

题解:

class Solution {
    public int rob(int[] nums) {
        int n = nums.length;
        if(n==0){
            return 0;
        }
        
        if(n == 1){
            return nums[0];
        }
        
        // 为了避免头尾同时被选到的情况,分别对去头和去尾的nums作打家劫舍,选择最优结果
        int res1 = subRob(nums, 0, n-2);
        int res2 = subRob(nums, 1, n-1);
        
        return res1>res2? res1:res2;
    }
    
    // 对nums的[l,r]区间进行打家劫舍,l<=r
    private int subRob(int[] nums, int l, int r){
        int[] dp = new int[r-l+1];
        dp[0] = nums[l];
        
        for(int k=l+1; k<=r; k++){
            dp[k-l] = Math.max(dp[k-l-1], nums[k]+(k-l-2>=0? dp[k-l-2]:0));
        }
        
        return dp[r-l];
    }
}

信件错排

题目描述: 有 N 个 信 和 信封,它们被打乱,求错误装信方式的数量。

题解: 定义一个数组 dp 存储错误方式数量,dp[i] 表示前 i 个信和信封的错误方式数量。假设第 i 个信装到第 j 个信封里面,而第 j 个信装到第 k 个信封里面。根据 i 和 k 是否相等,有两种情况:

  • i == k,交换 i 和 k 的信后,它们的信和信封在正确的位置,但是其余 i-2 封信有 dp[i-2] 种错误装信的方式。由于 j 有 i-1 种取值,因此共有 (i-1)*dp[i-2] 种错误装信方式。
  • i != k,交换 i 和 j 的信后,第 i 个信和信封在正确的位置,其余 i-1 封信有 dp[i-1] 种错误装信方式。由于 j 有 i-1 种取值,因此共有 (i-1)*dp[i-1] 种错误装信方式。

综上所述,错误装信数量方式数量为:

d p [ i ] = ( i − 1 ) ∗ d p [ i − 1 ] + ( i − 1 ) ∗ d p [ i − 2 ] dp[i] = (i-1)*dp[i-1]+(i-1)*dp[i-2] dp[i]=(i1)dp[i

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值