算法|9.从暴力递归到动态规划2

news2024/11/25 10:29:58

9.算法|从暴力递归到动态规划2

1.数字字符串转英文字符串

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

解题思路:

  • 边界判断1:能够不被阻挡的走到最后,说明这个决策正确,返回1
  • 边界判断2:0不能单独存在,若存在,决策失误
  • 普遍位置决策:单独转化必有,能不能拉下一个转换需要对它是不是存在以及存在之后和前边的结合在不在1~26之间这两个条件进行考察
  • dp改写的时候普遍位置存在是在当前字符不是’0‘的基础上的。

核心代码:

递归代码:

public static int number(String str) {
    char[] s=str.toCharArray();
    if(s==null||str.length()==0){
        return 0;
    }
    return process(s,0);
}

public static int process(char[] str, int index) {
    if(index==str.length){
        return 1;
    }
    if(str[index]=='0'){
        return 0;
    }
    int ways=process(str,index+1);
    if(index+1<str.length&&(str[index]-'0')*10+str[index+1]-'0'<27){
        ways+=process(str,index+2);
    }
    return ways;
}

dp代码:

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<str.length&&(str[i]-'0')*10+str[i+1]-'0'<27){
                ways+=dp[i+2];
            }
            dp[i]=ways;
        }
    }
    return dp[0];
}

测试代码:略

测试结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WhJYjV8G-1685240688357)(F:\typora插图\image-20230527213816410.png)]

累计和对半数组划分类问题

2.奇偶不敏感型

题意:给定一个正数数组arr,请把arr中所有的数分成两个集合,尽量让两个集合的累加和接近,返回最接近的情况下,较小集合的累加和

解题思路:

  • 主过程先将边界条件判断出来,和的一半计算出来

  • 子过程边界条件注意:rest<0没有必要了,注意,这里要的是最小的累加和,所以i有效判断之后返回的值应该是当前下标的值,所以返回的值如果不有效的话,不能干扰结果(满足条件的最大值),所以我们设定为-1;相应的如果i==arr.length,说明中间没有阻挡,这条路是个有效决策,返回0即可

  • 不超过rest说明当前已经求的是较小集合的累加和了,所以取的不是最小值,是满足条件的最大值!!!!!

  • 改写dp的时候注意return 换成dp时,看是不是需要加else

  • 改过之后,一次通过!!!!!!!!!(泰裤辣泰裤辣hhh)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yPRhXuWe-1685240688358)(F:\typora插图\image-20230528094029064.png)]

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NuVGtcd6-1685240688358)(F:\typora插图\image-20230528094049346.png)]

核心代码:

递归代码:

public static int right(int[] arr) {
    if (arr == null || arr.length < 2) {
        return 0;
    }
    int sum = 0;
    for (int cur : arr) {
        sum += cur;
    }
    return process(arr, 0, sum / 2);
}

public static int process(int[] arr, int i, int rest) {
    if (rest < 0) {
        return Integer.MAX_VALUE;
    }
    if (i == arr.length) {
        return 0;
    }
    int p1 = process(arr, i + 1, rest);
        int next = process(arr, i + 1, rest - arr[i]);
        if (next != -1) {
            int p2 = arr[i] + next;
            return Math.max(p1, p2);
        }
    return p1;
}

dp代码:

public static int dp(int[] arr) {
    if (arr == null || arr.length < 2) {
        return 0;
    }
    int sum = 0;
    for (int num : arr) {
        sum += num;
    }
    sum /= 2;
    int N = arr.length;
    int[][] dp = new int[N + 1][sum + 1];
    for (int i = N - 1; i >= 0; i--) {
        for (int rest = 0; rest <= sum; rest++) {
            int p1 = dp[i + 1][rest];
                int next = (rest - arr[i] < 0) ? -1 : dp[i + 1][rest - arr[i]];
                if (next != -1) {
                    int p2 = arr[i] + next;
                    dp[i][rest] = Math.max(p1, p2);
                } else {
                    dp[i][rest] = p1;
                }
        }
    }
    return dp[0][sum];
}

测试代码:略

测试结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m6PjEjaT-1685240688359)(F:\typora插图\image-20230528092117379.png)]

3.奇偶敏感型

题意:给定一个正数数组arr,请把arr中所有的数分成两个集合,如果arr长度为偶数,两个集合包含数的个数要一样多;如果arr长度为奇数,两个集合包含数的个数必须只差一个请尽量让两个集合的累加和接近,返回最接近的情况下,较小集合的累加和。

解题思路:

  • 相较于上题,本题需要多加一个可变参数,控制集合的个数,分为奇数情况和偶数情况
  • 偶数情况只能是一半一半,没的说;
  • 奇数要累计和最接近一半的那个(补集一定大于一半),但是此时这个最小集合的个数可能是奇数个也可能是偶数个,我们要个数和和都满足我们要求的小于和一般的最大值,重点理解这个最大值是怎么来的!!
  • 可变参数增加,对应的dp表的维度也要增加一个,变成三维的了

核心代码:

递归代码:

public static int right(int[] arr) {
    if (arr == null || arr.length < 2) {
        return 0;
    }
    int sum = 0;
    for (int cur : arr) {
        sum += cur;
    }
    if ((arr.length & 1) == 0) {
        return process(arr, 0, arr.length / 2, sum / 2);
    } else {
        return Math.max(process(arr, 0, arr.length / 2, sum / 2), process(arr, 0, arr.length / 2 + 1, sum / 2));
    }
}

public static int process(int[] arr, int i, int picks, int rest) {
    if (rest < 0) {
        return -1;
    }
    if (i == arr.length) {
        return picks == 0 ? 0 : -1;
    }
    int p1 = process(arr, i + 1, picks, rest);
    int next = process(arr, i + 1, picks - 1, rest - arr[i]);
    if (next != -1) {
        int p2 = arr[i] + next;
        return Math.max(p1, p2);
    } else {
        return p1;
    }
}

dp代码:

public static int dp(int[] arr) {
    if (arr == null || arr.length < 2) {
        return 0;
    }
    int sum = 0;
    for (int num : arr) {
        sum += num;
    }
    sum /= 2;
    int N = arr.length;
    int M = (N + 1) / 2;
    int[][][] dp = new int[N + 1][M + 1][sum + 1];
    for (int i = 0; i <= N; i++) {
        for (int j = 0; j <= M; j++) {
            for (int k = 0; k <= sum; k++) {
                dp[i][j][k] = -1;
            }
        }
    }
    for (int rest = 0; rest <= sum; rest++) {
        dp[N][0][rest] = 0;
    }
    for (int i = N - 1; i >= 0; i--) {
        for (int picks = 0; picks <= M; picks++) {
            for (int rest = 0; rest <= sum; rest++) {
                int p1 = dp[i + 1][picks][rest];
                int next = (rest - arr[i] < 0 || picks - 1 < 0) ? -1 : dp[i + 1][picks - 1][rest - arr[i]];
                if (next != -1) {
                    int p2 = arr[i] + next;
                    dp[i][picks][rest] = Math.max(p1, p2);
                } else {
                    dp[i][picks][rest] = p1;
                }
            }
        }
    }
    if ((arr.length & 1) == 0) {
        return dp[0][arr.length / 2][sum];
    } else {
        return Math.max(dp[0][arr.length / 2][sum], dp[0][(arr.length / 2) + 1][sum]);
    }
}

测试代码:略

测试结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i5vf8kMT-1685240688359)(F:\typora插图\image-20230528095650182.png)]

4.最小路径和

题意:给定一个二维数组matrix,一个人必须从左上角出发,最后到达右下角
沿途只可以向下或者向右走,沿途的数字都累加就是距离累加和,返回最小距离累加和

解题思路:

  • 递归代码注意尝试的方向

核心代码:

递归代码:

public static int minPathSum(int[][] m){
    if (m == null || m.length == 0 || m[0] == null || m[0].length == 0) {
        return 0;
    }
    return process(m,m.length-1,m[0].length-1);
}

private static int process(int[][] m, int curR, int curC) {
    if(curC>=m[0].length||curR>=m.length){
        return 0;
    }
    if(curR==0&&curC==0){
        return m[0][0];
    }
    if(curR==0){
        return m[0][curC]+process(m,0,curC-1);
    }
    if(curC==0){
        return m[curR][0]+process(m,curR-1,0);
    }
    return m[curR][curC]+Math.min(process(m,curR-1,curC),process(m,curR,curC-1));
}

dp代码:

public static int dp(int[][] m) {
    if (m == null || m.length == 0 || m[0] == null || m[0].length == 0) {
        return 0;
    }
    int row = m.length;
    int col = m[0].length;
    int[][] dp = new int[row][col];
    dp[0][0] = m[0][0];
    for (int i = 1; i < row; i++) {
        dp[i][0] = dp[i - 1][0] + m[i][0];
    }
    for (int j = 1; j < col; j++) {
        dp[0][j] = dp[0][j - 1] + m[0][j];
    }
    for (int i = 1; i < row; i++) {
        for (int j = 1; j < col; j++) {
            dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + m[i][j];
        }
    }
    return dp[row - 1][col - 1];
}

测试代码:

// for test
public static int[][] generateRandomMatrix(int rowSize, int colSize) {
    if (rowSize < 0 || colSize < 0) {
        return null;
    }
    int[][] result = new int[rowSize][colSize];
    for (int i = 0; i != result.length; i++) {
        for (int j = 0; j != result[0].length; j++) {
            result[i][j] = (int) (Math.random() * 100);
        }
    }
    return result;
}

// for test
public static void printMatrix(int[][] matrix) {
    for (int i = 0; i != matrix.length; i++) {
        for (int j = 0; j != matrix[0].length; j++) {
            System.out.print(matrix[i][j] + " ");
        }
        System.out.println();
    }
}

public static void main(String[] args) {
    int rowSize = 10;
    int colSize = 10;
    int[][] m = generateRandomMatrix(rowSize, colSize);
    System.out.println(minPathSum(m));
    System.out.println(dp(m));

}

测试结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y2zmzEqv-1685240688360)(F:\typora插图\image-20230528101856049.png)]

改不了dp的递归举例:贴纸问题(略)

题意:给定一个字符串str,给定一个字符串类型的数组arr,出现的字符都是小写英文arr每一个字符串,代表一张贴纸,你可以把单个字符剪开使用,目的是拼出str来返回需要至少多少张贴纸可以完成这个任务
例子:str= “babac”,arr = {“ba”,“c”,“abcd”},ba + ba + c 3,abcd + abcd 2 abcd+ba 2,所以返回2

解题思路:

  • 词频统计

核心代码:

递归代码:

public static int minStickers2(String[] stickers, String target) {
    int N = stickers.length;
    // 关键优化(用词频表替代贴纸数组)
    int[][] counts = new int[N][26];
    for (int i = 0; i < N; i++) {
        char[] str = stickers[i].toCharArray();
        for (char cha : str) {
            counts[i][cha - 'a']++;
        }
    }
    int ans = process2(counts, target);
    return ans == Integer.MAX_VALUE ? -1 : ans;
}

// stickers[i] 数组,当初i号贴纸的字符统计 int[][] stickers -> 所有的贴纸
// 每一种贴纸都有无穷张
// 返回搞定target的最少张数
// 最少张数
public static int process2(int[][] stickers, String t) {
    if (t.length() == 0) {
        return 0;
    }
    // target做出词频统计
    // target  aabbc  2 2 1..
    //                0 1 2..
    char[] target = t.toCharArray();
    int[] tcounts = new int[26];
    for (char cha : target) {
        tcounts[cha - 'a']++;
    }
    int N = stickers.length;
    int min = Integer.MAX_VALUE;
    for (int i = 0; i < N; i++) {
        // 尝试第一张贴纸是谁
        int[] sticker = stickers[i];
        // 最关键的优化(重要的剪枝!这一步也是贪心!)
        if (sticker[target[0] - 'a'] > 0) {
            StringBuilder builder = new StringBuilder();
            for (int j = 0; j < 26; j++) {
                if (tcounts[j] > 0) {
                    int nums = tcounts[j] - sticker[j];
                    for (int k = 0; k < nums; k++) {
                        builder.append((char) (j + 'a'));
                    }
                }
            }
            String rest = builder.toString();
            min = Math.min(min, process2(stickers, rest));
        }
    }
    return min + (min == Integer.MAX_VALUE ? 0 : 1);
}

从左向右尝试模型总结2

dp改写规则:

  • 进入嵌套的for循环后,看是不是需要加if判断条件。因为递归中是前边的边界判断完才能执行普遍位置的逻辑的,其实也相当于一个else分支,要记得判断!!!
  • 贴纸问题改不了dp的递归原因:两个都是字符串长度/个数不确定,表的大小可能非常大,此时使用缓存表即HashMap

例题总结:

  • 数字字符串转英文字符串:尝试策略——决策位置到头了没被挡,返回1;当前决策位置值为‘0’,之前的有问题,返回0;否则就是自己决策数量和拉上邻居决策的总数量。改dp注意:参数范围,初始方向
  • 奇偶不敏感型累加和对半数组划分:rest<0;i==arr.length;next=-1;取的满足条件的最大值
  • 奇偶敏感型累加和对半数组划分:rest<0;i==arr.length(picks);两个取的满足条件的最大值
  • 最小路径和:尝试策略的方向倒着的,改成的dp是顺着的
  • 贴纸问题:次品统计。改不了dp

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

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

相关文章

windows安装python开发环境

最近因工作需要&#xff0c;要学习一下python&#xff0c;所以先安装一下python的开发环境&#xff0c;比较简单 下载和安装Python 首先&#xff0c;在浏览器中打开Python的官方网站&#xff08;https://www.python.org/downloads/) 然后&#xff0c;从该网站下载与你的操…

NCI架构-1

1、NFCC和DH通过物理连线相连&#xff0c;物理连线对应为Transport Layer&#xff08;传输层&#xff09;&#xff0c;支持SPI、I2C、UART、USB等&#xff1b; 2、DH中所有和NFC相关的应用程序都可视为DH-NFCEE(EE:Execution Enviroment)&#xff0c;图左的NFCEE模块可运行一些…

Linux系统中源码安装1.8.x版本Arduino IDE

本文内容参考&#xff1a; Ubuntu22.04安装Arduino IDE及Arduino UNO&#xff08;使用CH341驱动&#xff09;调试方法__KILLMILEDC_的博客-CSDN博客 在Linux上下载arduino_不说话的白帽子的博客-CSDN博客 https://guoqing.blog.csdn.net/article/details/88913063?spm1001.…

【JVM】8. 对象实例化及直接内存

文章目录 8.1. 对象实例化8.1.1. 创建对象的方式8.1.2. 创建对象的步骤1. 判断对象对应的类是否加载、链接、初始化2. 为对象分配内存3. 处理并发问题4. 初始化分配到的内存5. 设置对象的对象头6. 执行init方法进行初始化 8.2. 对象内存布局8.2.1. 对象头&#xff08;Header&am…

python+vue新能源汽车在线租赁管理系统pycharm项目

开发语言&#xff1a;Python 框架&#xff1a;django/flask Python版本&#xff1a;python3.7.7 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;PyCharm 在当今高度发达的信息中&#xff0c;信息管理改革已成为一种更加广泛和全面的趋势。 “新…

SpringBoot——原理(自动配置+原理分析@Conditional)

在上一篇有说到&#xff0c;进行源码跟踪时可以看见一个以Conditional开头的注解&#xff0c;这些都是条件装配的注解。 加在方法上时只对该方法生效&#xff0c;加在类上时是对整个配置类都有效。 这里只说三个常用的Conditional的子注解 案例演示 在启动类上加上一个Enabl…

第二章:ShardingSphere简介

什么是ShardingSphere 何为ShardingSphere呢?其实我们总结如下三点就能很好的理解: 1、一整套开源的分布式数据库中间件解决方案 2、有三个产品组成:Sharding-JDBC、Sharding-Proxy、Sharding-Sidecar(规划中) 3、他的定位是关系型数据库的中间件,在分布式环境下合理的…

【20】SCI易中期刊推荐——计算机信息系统工程电子与电气(中科院3区)

💖💖>>>加勒比海带,QQ2479200884<<<💖💖 🍀🍀>>>【YOLO魔法搭配&论文投稿咨询】<<<🍀🍀 ✨✨>>>学习交流 | 温澜潮生 | 合作共赢 | 共同进步<<<✨✨ 📚📚>>>人工智能 | 计算机视觉…

(转载)matlab遗传算法工具箱

以下内容大部分来源于《MATLAB智能算法30个案例分析》&#xff0c;仅为学习交流所用。 1理论基础 1.1遗传算法概述 遗传算法(genetic algorithm,GA)是一种进化算法,其基本原理是仿效生物界中的“物竞天择、适者生存”的演化法则。遗传算法是把问题参数编码为染色体,再利用迭代…

Qiskit系列(1)---Qiskit安装

1.qiskit与anaconda简介 Qiskit并不是一门独立的语言&#xff0c;它是基于Python的一个框架&#xff0c;就好比Pytorch, Tensorflow。而Qiskit这个框架需要配套一些其他的package&#xff08;各种大小DLC&#xff09;一起运行&#xff0c;这些运行Qiskit所必须的package就构成了…

vue前端分页功能怎么实现

Vue前端分页功能可以通过以下几个步骤实现&#xff1a; 1. 安装分页组件库&#xff08;如vue-pagination-2&#xff09;&#xff1a; bash npm install vue-pagination-2 2. 在Vue项目中引入并注册分页组件&#xff1a; javascript import Vue from vue; import Pagination fr…

【商品详情 +关键词搜索】API 接口系列

首先&#xff0c;大家要到官方主页去申请一个 appkey&#xff0c;这个是做什么用的呢&#xff1f;App Key 是应用的唯一标识&#xff0c;TOP 通过 App Key 来鉴别应用的身份。AppSecret 是 TOP 给应用分配的密钥&#xff0c;开发者需要妥善保存这个密钥&#xff0c;这个密钥用来…

增强语言模型导读

以ChatGPT为主的大语言模型出现已有半年时间&#xff0c;研究逐渐从针对模型本身的进化和功能&#xff0c;延展到如何更为有效地利用大模型&#xff0c;将它与其它工具结合&#xff0c;落地&#xff0c;以解决实际领域中的问题。 这里的增强主要指让大语言模型&#xff08;LM&…

【21】SCI易中期刊推荐——计算机科学人工智能领域(中科院4区)

💖💖>>>加勒比海带,QQ2479200884<<<💖💖 🍀🍀>>>【YOLO魔法搭配&论文投稿咨询】<<<🍀🍀 ✨✨>>>学习交流 | 温澜潮生 | 合作共赢 | 共同进步<<<✨✨ 📚📚>>>人工智能 | 计算机视觉…

Unity 动画系统基本概念

一、动画的基本概念 1、帧 在古代&#xff0c;一幅字画叫一帧&#xff0c;而在计算机中&#xff0c;每次渲染完毕一幅画面并显示出来&#xff0c;这一幅画就是一帧。 连续切换的帧就形成了动态的画面。每秒刷新帧的次数称为频率&#xff0c;单位是FPS&#xff08;Frames Per…

JavaEE Tomcat Servelet第一个helloworld程序

Tomcat & Servelet第一个程序helloworld&#xff01; 文章目录 JavaEE & Tomcat & 第一个Servelet程序1. HTTP服务器 - Tomcat1.1 Tomcat的目录结构&#xff1a;1.2 启动Tomcat1.3 Tomcat的优点 2. Servelet框架2.1 创建Maven项目2.2 引入依赖2.3 创建目录2.4 写代…

Mac电脑读写移动硬盘软件Tuxera NTFS2023中文版

日常工作中&#xff0c;我们经常会使用移动硬盘拷贝文件&#xff0c;因为移动硬盘传输文件方便、传输速度快。但我们在mac电脑上使用移动硬盘却发现硬盘无法正常读写。本文向大家介绍mac能读写的移动硬盘有哪些以及移动硬盘怎么在mac上读写。 一、Mac能读写的移动硬盘有哪些 移…

数据挖掘(5.1)--贝叶斯分类

目录 前言 正文 1.主观概率 2.贝叶斯定理 1.基础知识 2.贝叶斯决策准则 3.极大后验假设 4.例题 2.朴素贝叶斯分类模型 朴素贝叶斯分类器的算法描述&#xff1a; 朴素贝叶斯算法特点 3.贝叶斯信念网 贝叶斯网络的建模包括两个步骤 贝叶斯信念网特点 开往夏天的列…

C++第七章:类

类 一、定义抽象数据类型1.1 定义抽象数据类型类的用户 1.2 定义一个书籍类引入this引入const成员函数类作用域和成员函数在类的外部定义成员函数定义一个返回this对象的函数 1.3 定义类相关的非成员函数定义read和print函数最终代码 1.4 构造函数合成的默认构造函数某些类不能…

真相只有一个——真正排名

这里写目录标题 1.题目描述2.解题思路3.代码展 所属专栏&#xff1a;脑筋急转弯❤️ &#x1f680; >博主首页&#xff1a;初阳785❤️ &#x1f680; >代码托管&#xff1a;chuyang785❤️ &#x1f680; >感谢大家的支持&#xff0c;您的点赞和关注是对我最大的支持…