暴力递归到动态规划(二)

news2024/11/29 8:02:31

请添加图片描述
⭐️前言⭐️

本篇文章是由暴力递归到动态规划篇章的第二篇。

🍉欢迎点赞 👍 收藏留言评论 📝私信必回哟😁

🍉博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言

🍉博客中涉及源码及博主日常练习代码均已上传GitHub


请添加图片描述

📍内容导读📍

  • 🍅背包问题
  • 🍅字符串转化
  • 🍅最长公共子序列(样本对应模型)
  • 🍅最长回文子序列(范围尝试模型)
  • 🍅跳马问题

🍅背包问题

题目:
背包问题
给定两个长度都为N的数组weights和values,weights[i]和values[i]分别代表 i号物品的重量和价值
给定一个正数bag,表示一个载重bag的袋子,装的物品不能超过这个重量
返回能装下的最大价值

题解思路1:
每个物品有选和不选两种情况,在背包容量充足的情况下,返回两种情况中的最大值
递归函数返回符合条件的情况下,所能获得的最大价值。

代码实现:

public class Knapsack {
    public static int maxValue(int[] w,int[] v,int bag) {
        if(w==null||v==null||w.length!=v.length||w.length==0||v.length==0) {
            return 0;
        }
        return process(w,v,0,bag);
    }

    // index:第index个物品
    // rest:背包的剩余容量
    public static int process(int[] w,int[] v,int index,int rest) {
        if(rest<0) {
            return -1;
        }
        if(index==w.length) {
            return 0;
        }
        int p1=process(w,v,index+1,rest);
        int p2=0;
        int next=process(w,v,index+1,rest-w[index]);
        if(next!=-1) {
            p2=v[index]+next;
        }
        return Math.max(p1,p2);
    }
}

题解思路2:(动态规划)
有状态相同的情况,所以可以通过缓存表来减少重复计算。
假设数组长度为4,背包容量为10,最后想要获得的结果就是dp[0][bag]位置的结果。

根据暴力递归的解法,来推断出dp表中填写的规则,最后返回所要位置的结果,
代码实现:

public class Knapsack {
    public static int dp(int[] w,int[] v,int bag) {
        if(w==null||v==null||w.length!=v.length||w.length==0||v.length==0) {
            return 0;
        }
        int N=w.length;
        int[][] dp=new int[N+1][bag+1];
        for (int index = N-1; index >=0 ; index--) {
            for (int rest = 0; rest <=bag ; rest++) {
                int p1=dp[index+1][rest];
                int p2=0;
                int next=rest-w[index]<0?-1:dp[index+1][rest-w[index]];
                if(next!=-1) {
                    p2=v[index]+next;
                }
                dp[index][rest]=Math.max(p1,p2);
            }
        }
        return dp[0][bag];
    }
}

🍅字符串转化

题目:
规定1和A对应、2和B对应、3和C对应…26和Z对应
那么一个数字字符串比如"111”就可以转化为:
“AAA”、“KA"和"AK”
给定一个只有数字字符组成的字符串str,返回有多少种转化结果

题解思路1:
从字符串的第i个字符来考虑转化情况,第一种是第i个字符单独转化,那么转化结果数即为从i+1位置考虑转化的结果数;第二种是第i个字符和第i+1个字符可以一起转化,那么转化结果数即为从i+2位置考虑转化的结果数。

代码实现:

public class CoverToLetterString {
    // str只含有数字字符0~9
    // 返回多少种转化方案
    public static int number(String str) {
        if(str==null||str.length()==0) {
            return 0;
        }
        return process(str.toCharArray(),0);
    }
    // str[0..i-1] 转化无需过问
    // str[i...]去转化,返回有多少种转化方法
    public static int process(char[] str, int i) {
        if(i==str.length) {  // 如果到最后,就是一种转化方法
            return 1;
        }
        // i没到最后,说明有字符
        if(str[i]=='0') {  // 之前的决定有问题
            return 0;
        }
        // str[i]!='0'
        // 可能性1,i单独转化
        int ways=process(str,i+1);
        // 可能性2,i和i+1一同转化
        if(i+1<str.length&&(str[i]-'0')*10+str[i+1]-'0'<27) {
            ways+=process(str,i+2);
        }
        return ways;
    }
}

题解思路2:
根据上边的暴力递归解法,可以改写出从右往左的动态规划版本,dp[i]表示str[i…]有多少种转化方式

代码实现:

public class CoverToLetterString {
    public static int dp(String s) {
        if(s==null||s.length()==0) {
            return 0;
        }
        char[] str=s.toCharArray();
        int N= str.length;
        int[] dp=new int[N+1];
        dp[N]=1;
        for (int i = N-1; i >=0 ; i--) {
            if(str[i]!='0') {
                int ways=dp[i+1];
                if(i+1<N&&(str[i]-'0')*10+str[i+1]-'0'<27) {
                    ways+=dp[i+2];
                }
                dp[i]=ways;
            }
        }
        return dp[0];
    }
}

🍅最长公共子序列(样本对应模型)

题目:https://leetcode.cn/problems/longest-common-subsequence/
给定两个字符串str1和str2,
返回这两个字符串的最长公共子序列长度
比如 : str1 = “a12b3c456d”,str2 = “1ef23ghi4j56k”
最长公共子序列是“123456”,所以返回长度6

模型解题:
该模型通常考虑两个样本的结尾边界情况

题解思路1:
考虑str1[0…i]和str2[0…j],这个范围上的最长公共子序列长度:
当str1以i=0结尾的时候,判断i与j位置的字符是否相同,相同返回1;不相同递归(i,j-1);
当str2以j=0的时候,判断i与j位置的字符是否相同,相同返回1;不相同递归(i-1,j);
当i、j都不为0时,
1:str1不考虑以i结尾;2:str2不考虑以j结尾;3:既考虑以i结尾,又考虑以j结尾。

代码实现:

public class LongestCommonSubsequence {
    public static int longestCommonSubsequence(String s1,String s2) {
        if(s1==null||s2==null||s1.length()==0||s2.length()==0) {
            return 0;
        }
        char[] str1=s1.toCharArray();
        char[] str2=s2.toCharArray();
        return process(str1,str2,str1.length-1,str2.length-1);
    }

    // 考虑str1[0...i]和str2[0...j],这个范围上的最长公共子序列长度
    public static int process(char[] str1,char[] str2,int i,int j) {
        if(i==0&&j==0) {  // 都只剩一个字符
            return str1[i]==str2[j]?1:0;
        }else if (i==0) {
            if(str1[i]==str2[j]) {
                return 1;
            }else {
                return process(str1,str2,i,j-1);
            }
        }else if(j==0) {
            if (str1[i]==str2[j]) {
                return 1;
            }else {
                return process(str1,str2,i-1,j);
            }
        }else {  // i!=0&&j!=0
            int p1=process(str1,str2,i-1,j);
            int p2=process(str1,str2,i,j-1);
            int p3=str1[i]==str2[j]?(1+process(str1,str2,i-1,j-1)):0;
            return Math.max(p1,Math.max(p2,p3));
        }
    }
}

题解思路2:
根据暴力递归来改写动态规划,用一张二维表来记录i、j位置的最长公共子序列,返回表的右下角的结果。

代码实现:

public class LongestCommonSubsequence {
    public static int longestCommonSubsequence(String s1,String s2) {
        if(s1==null||s2==null||s1.length()==0||s2.length()==0) {
            return 0;
        }
        char[] str1=s1.toCharArray();
        char[] str2=s2.toCharArray();
        int N=str1.length;
        int M=str2.length;
        int[][] dp=new int[N][M];
        dp[0][0]=str1[0]==str2[0]?1:0;
        for (int j = 1; j <M ; j++) {
            dp[0][j]=str1[0]==str2[j]?1:dp[0][j-1];
        }
        for (int i = 1; i <N ; i++) {
            dp[i][0]=str1[i]==str2[0]?1:dp[i-1][0];
        }
        for (int i = 1; i <N ; i++) {
            for (int j = 1; j <M; j++) {
                int p1=dp[i-1][j];
                int p2=dp[i][j-1];
                int p3=str1[i]==str2[j]?(1+dp[i-1][j-1]):0;
                dp[i][j]=Math.max(p1,Math.max(p2,p3));
            }
        }
        return dp[N-1][M-1];
    }
}

🍅最长回文子序列(范围尝试模型)

题目:https://leetcode.cn/problems/longest-palindromic-subsequence/description/
给定一个字符串str,返回这个字符串的最长回文子序列长度
比如 : str = “a12b3c43def2ghi1kpm”
最长回文子序列是“1234321”或者“123c321”,返回长度7

模型解题:
该模型通常考虑样本的开头和结尾的判定情况

题解思路1:
将字符串逆序,与原字符串求最长公共子序列,得到的结果即为最长回文子序列。

题解思路2:
考虑str[L…R]范围内的最长回文子序列长度,穷举所有可能性,返回最大的结果:
1、最长回文子序列既不以L开头,也不以R结尾
2、最长回文子序列以L开头,不以R结尾
3、最长回文子序列不以L开头,以R结尾
4、最长回文子序列以L开头,R结尾

代码实现:

public class PalindromeSubsequence {
    public static int lpsl1(String s) {
        if(s==null||s.length()==0) {
            return 0;
        }
        char[] str=s.toCharArray();
        return f(str,0,str.length-1);
    }

    // str[L...R]最长回文子序列长度返回
    public static int f(char[] str,int L,int R) {
        if(L==R) {
            return 1;
        }
        if(L==R-1) {
            return str[L]==str[R]?2:1;
        }
        int p1=f(str,L+1,R-1);
        int p2=f(str,L,R-1);
        int p3=f(str,L+1,R);
        int p4=str[L]!=str[R]?0:(2+f(str,L+1,R-1));
        return Math.max(Math.max(p1,p2),Math.max(p3,p4));
    }
}

题解思路3:
有两个可变参数,可以在这里插入图片描述
构建出dp表,来存储每个范围的最长回文子序列长度,

可以先根据base case,来完成对角线和紧挨对角线两条斜线的初始化,然后再根据依赖关系,完成剩余位置的填写,最后返回标记位置的结果即可。

代码实现:

public class PalindromeSubsequence {
    public static int longestPalindromeSubsequence(String s) {
        if(s==null||s.length()==0) {
            return 0;
        }
        if (s.length()==1) {
            return 1;
        }
        char[] str=s.toCharArray();
        int N=str.length;
        int[][] dp=new int[N][N];
        dp[N-1][N-1]=1;
        // 如果L==R,dp值为1;如果str[L]==str[R-1]dp值为2,否则为1
        for (int i = 0; i < N-1; i++) {
            dp[i][i]=1;
            dp[i][i+1]=str[i]==str[i+1]?2:1;
        }
        // 其余位置的dp值,依赖于左、左下、下三个位置的dp值
        for (int i=N-3;i>=0;i--) {
            for (int j = i+2; j < N; j++) {
                dp[i][j]=Math.max(dp[i][j-1],dp[i+1][j]);
                if(str[i]==str[j]) {
                    dp[i][j]=Math.max(dp[i][j],2+dp[i+1][j-1]);
                }
            }
        }
        return dp[0][N-1];
    }
}

🍅跳马问题

题目:
请同学们自行搜索或者想象一个象棋的棋盘,
然后把整个棋盘放入第一象限,棋盘的最左下角是(0,0)位置
那么整个棋盘就是横坐标上9条线、纵坐标上10条线的区域
给你三个 参数 x,y,k
返回“马”从(0,0)位置出发,必须走k步
最后落在(x,y)上的方法数有多少种?

题解思路1:
如果马在棋盘的中间位置,它一步可以到达八个不同的位置,设置base case出界返回0,如果剩0步就判断是不是到达了指定位置,这样去累加八个位置的可能性,最后返回的即为结果。

代码实现:

public class HorseJump {
    // 当前来到的位置是(x,y)
    // 还剩rest步需要跳
    // 跳完rest步,正好跳到a,b的方法数是多少
    public static int jump(int a,int b,int k) {
        return process(0,0,k,a,b);
    }

    public static int process(int x,int y,int rest,int a,int b) {
        if(x<0||x>9||y<0||y>8) {
            return 0;
        }
        if(rest==0) {
            return (x==a&&y==b)?1:0;
        }
        int ways = process(x + 2, y + 1, rest - 1, a, b);
        ways += process(x + 1, y + 2, rest - 1, a, b);
        ways += process(x - 1, y + 2, rest - 1, a, b);
        ways += process(x - 2, y + 1, rest - 1, a, b);
        ways += process(x - 2, y - 1, rest - 1, a, b);
        ways += process(x - 1, y - 2, rest - 1, a, b);
        ways += process(x + 1, y - 2, rest - 1, a, b);
        ways += process(x + 2, y - 1, rest - 1, a, b);
        return ways;
    }
}

题解思路2:
在递归中有x,y,rest三个可变参数,所以可以根据依赖关系来构建一个三维表,存储不同位置的结果数,最后返回dp(0,0,k)即为所求。
依赖关系都是rest-1的,所以可以一层一层的填充。

代码实现:

public class HorseJump {
    public static int dp(int a,int b,int k) {
        int[][][] dp=new int[10][9][k+1];
        dp[a][b][0]=1;
        for (int rest = 1; rest <=k; rest++) {
            for (int x = 0; x < 10; x++) {
                for (int y = 0; y < 9; y++) {
                    int ways = pick(dp, x + 2, y + 1, rest - 1);
                    ways += pick(dp, x + 1, y + 2, rest - 1);
                    ways += pick(dp, x - 1, y + 2, rest - 1);
                    ways += pick(dp, x - 2, y + 1, rest - 1);
                    ways += pick(dp, x - 2, y - 1, rest - 1);
                    ways += pick(dp, x - 1, y - 2, rest - 1);
                    ways += pick(dp, x + 1, y - 2, rest - 1);
                    ways += pick(dp, x + 2, y - 1, rest - 1);
                    dp[x][y][rest] = ways;
                }
            }
        }
        return dp[0][0][k];
    }

    public static int pick(int[][][] dp,int x,int y,int rest) {
        if(x<0||x>9||y<0||y>8) {
            return 0;
        }
        return dp[x][y][rest];
    }
}

⭐️最后的话⭐️
总结不易,希望uu们不要吝啬你们的👍哟(^U^)ノ~YO!!如有问题,欢迎评论区批评指正😁

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/620137.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

扫码出入库系统在哪些行业使用率最高?服务业绑得最紧密

什么是扫码出入库系统 扫码出入库系统是一种流行的库存管理系统&#xff0c;它使用二维码、条形码或RFID等技术来管理仓库内的物品出入库情况。 使用扫码出入库系统&#xff0c;用户可以通过扫描物品的二维码或条形码&#xff0c;快速地将物品信息录入系统中&#xff0c;同时…

采用sysbench压测mysql详解

文章目录 安装sysbench工具基于sysbench构造测试表和测试数据数据库读写性能测试数据库读性能测试数据库删除性能测试数据库更新索引字段性能测数据库更新非索引字段性能测试数据库插入数据性能测试数据库写性能测试执行完成压测之后可以将run改成cleanup&#xff0c;清除数据 …

LegalAI公开数据集的整理、总结及介绍(持续更新ing…)

诸神缄默不语-个人CSDN博文目录 最近更新日期&#xff1a;2023.6.7 最早更新日期&#xff1a;2023.6.7 文章目录 1. 司法判决预测2. 通用语料3. 其他集成项目4. 推理5. NLU6. NLG1 QA2 文本摘要 7. 信息抽取1 命名实体识别2 句子边界检测&#xff08;分句&#xff09; 1. 司法…

青岛科技大学|物联网工程|物联网定位技术(第二讲)|15:00

目录 物联网定位技术&#xff08;第二讲&#xff09; 1. 卫星的轨道高度与覆盖区域有何关系&#xff0c;试画图给予说明覆盖区地心角与覆盖面积的关系 2. 试给出实际的卫星地面覆盖区和用户空间可视区所对应的半地心角的公式并请给予解释 3. 定位导航卫星为什么一般不采用同…

【集群】LVS负载均衡群集

文章目录 前言一、企业群集应用概述1. 群集的含义1.1 群集的特点1.2 扩展服务器的方式 2. 群集的类型2.1 负载均衡群集&#xff08;Load Balance Cluster&#xff09;2.2 高可用群集&#xff08;High Availability Cluster&#xff09;2.3 高性能运算群集&#xff08;High Perf…

软考A计划-电子商务设计师-模拟试题卷七

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

有一种附件叫做V2附件

大家好&#xff0c;才是真的好。 一般而言&#xff0c;Notes中上传的附件都会对应到某个富文本字段中&#xff0c;这样附件易于处理&#xff0c;也容易进行排版。 最简单的案例就是我们的Notes邮件&#xff0c;附件可以附加在正文中&#xff0c;如下图&#xff1a; 还有我们…

新入职一家公司,接手了个从零开始的项目

开发流程 一个完整的从零开始开发的项目&#xff0c;会涉及到功能设计、数据库设计、项目框架搭建、接口设计与实现等流程&#xff0c;具体可以参考下图。 与我们后端开发有关的主要是功能设计、数据库设计、接口设计与实现这三部分&#xff0c;当然接口设计与实现中也包含项目…

chatgpt赋能python:Python如何快速SEO

Python如何快速SEO Python作为一种通用编程语言&#xff0c;广泛应用于各行各业&#xff0c;包括网站开发和SEO。SEO&#xff08;Search Engine Optimization&#xff09;是通过调整网站的结构和内容来提高其在搜索引擎排名中的位置&#xff0c;从而提高网站的流量和收益。Pyt…

【百问百答】可靠性基础知识第四期

1. IP等级的主要测试标准有哪些? 主要参考标准有GB 4208和IEC 60598&#xff0c; 其中也可以具体参考产品标准&#xff0c; 例如LED灯具参考标准为GB 7000&#xff0c; 汽车电子产品可以参考GB/T 28046.3等等。 2.IP等级可分为几个等级? 根据GB4208标准防止固定异物进入&…

阿里云 Serverless 容器服务全面升级:新增组件全托管、AI 镜像秒级拉取能力

6 月 1 日在阿里云峰会粤港澳大湾区上&#xff0c;阿里云智能云原生应用平台总经理丁宇宣布&#xff0c;Serverless 容器服务 ASK 全面升级&#xff0c;进一步帮助企业和开发者降本提效。 Gartner 曾预测&#xff0c;2023 年 70% 的 AI 应用将基于容器和 Serverless 技术开发。…

开源“上天入地”的本领都在这!2023 开放原子全球开源峰会「开源展览」一文拿捏!

2023 开放原子全球开源峰会 将于 6 月 11-13 日正式举办 开源领域新技术、新应用、新热点 Show Time&#xff01; 前沿开源展览汇 互动体验项目 让每一位参会者融入开源技术新世界&#xff01; 还有精彩的娱乐项目和丰厚礼品 一网打尽&#xff01; 抢先揭秘&#xff0c;一…

【Springboot】基于AOP机制的前置通知以及Cookies记录用户操作日志

文章目录 前言1. 添加依赖2. 创建自定义注解LogAnnotation3. 创建日志记录类型3. 编写切面逻辑4. 完善切面层&#xff0c;获取详细的请求信息4.1 获取自定义注解上的属性值4.2 通过Cookies获取用户信息4.3 获取执行时间4.4 日志实体类以及对应数据库类型 5.最后实现的结果 前言…

Spring Authorization Server扩展实现OAuth2.0的密码模式

写在前面 Spring官方已经停止对Spring Security Oauth2的维护&#xff0c;项目和相关文档也被移除 Spring Authorization Server是官方新推出的OAuth2.1和OpenID Connect1.0的实现 两个主要的版本&#xff0c;0.4.x&#xff1a;jdk8。1.x: jdk17 这里用的版本是0.4.1 OAuth2…

A Comprehensive Survey of Neural Architecture Search: Challenges and Solutions

这是NAS综述系列的第二篇文章&#xff0c;针对《A Comprehensive Survey of Neural Architecture Search:Challenges and Solutions》的翻译。 神经架构搜索综述&#xff1a;挑战与解决方案 摘要1 引言1.1 动机1.2 我们的贡献和相关综述1.3 文章组织 2 早期NAS的特征3 优化策略…

SpringBoot之Spring Data JPA入门学习2

我们继续使用上一章的环境。SpringBoot之Spring Data JPA入门学习 一、自动生成数据 我们修改一下实体 增加了几个注解&#xff1a; CreationTimestamp 自动生成创建时间。 UpdateTimestamp 自动生成更新时间。 使用这两个注解我们还需要在类上加上两个注解DynamicInsert和…

【unity造轮子】排序排行榜的制作

List类中有一个【Sort方法】 可以非常快速的对【整数类】 或者【小数类】元素进行升序 public class TestCompare MonoBehaviour {public List<int>numbers;private void Start(){numbersnew List<int>(){20,10,30,70,60,40,50,90,80,100}:}private void Update()…

stable diffusion图片资源分享和模型推荐,好用的模型有哪些呢?

前言 这篇文章主要是分享我的图片和推荐一些好用的模型&#xff0c;模型不在多在于精&#xff0c;基于几个好的大模型适当下载一下LORA模型&#xff0c;就能画出非常好的图片&#xff0c;多话不说 图片分享 简单展示 详情请看&#xff1a;https://space.bilibili.com/109890…

Amazon Web Services (AWS)上的 OpenText 信息管理(IM) 解决方案

Amazon Web Services (AWS)上的 OpenText 信息管理(IM) 解决方案 OpenText 行业领先的信息管理(IM) 解决方案作为完全托管的服务提供&#xff0c;以 Amazon 公有云环境的安全性、可扩展性和性能为后盾&#xff0c;实现业务数字化转型并推动创新。 价值 降低运营成本30%以上&…

ldap服务安装,客户端安装,ldap用户登录验证测试

安装服务端 # 安装ldap服务 docker run -p 389:389 -p 636:636 \ --name openldap \-v /home/manager/testldap:/testldap \ --env LDAP_ORGANISATION"admin" \ --env LDAP_DOMAIN"hadoop.apache.org" \ --env LDAP_ADMIN_PASSWORD"Dmpxxx" \ -…