算法入门篇九 暴力递归

牛客网 左程云老师的算法入门课

暴力递归

原则

 汉诺塔问题

问题

  • 打印n层汉诺塔从左边移动到最右边的过程 

思想

一共六个过程,左到右、左到中,中到左,中到右,右到左,右到中,互相嵌套使用

左到右

  • 将1-》N-1移动到中间的那个杆上
  • 将N从最左边移动到最右边
  • 将1》-N-1移动到最右边的那个杆上

左到中

  • 将1-N-1从左移动到右
  • N从左移动到中
  • 将1-》N-1从右移动到中

。。。。。。

代码

package class08;public class Code01_Hanoi {public static void hanoi(int n) {if (n > 0) {func(n, "左", "右", "中");}}// 1~i 圆盘 目标是from -> to, other是另外一个public static void func(int N, String from, String to, String other) {if (N == 1) { // baseSystem.out.println("Move 1 from " + from + " to " + to);} else {func(N - 1, from, other, to);System.out.println("Move " + N + " from " + from + " to " + to);func(N - 1, other, to, from);}}public static void printAllWays(int n) {leftToRight(n);}public static void leftToRight(int n) {if(n== 1) {System.out.println("Move 1 from left to right");return ;}leftToMid(n-1);System.out.println("Move " +n + " from left to right");midToRight(n-1);}public static void leftToMid(int n) {if(n== 1) {System.out.println("Move 1 from left to mid");return ;}leftToRight(n-1);System.out.println("Move " +n + " from left to mid");rightToMid(n-1);}public static void midToRight(int n) {}public static void rightToMid(int n) {}public static void main(String[] args) {int n = 3;hanoi(n);}}

例子

打印一个字符串的全部子序列,包括空字符串

(从左往右依次尝试的模型)

  • 需要保证字符的前后顺序
  • “abc” =》a,b,c,ab,ac,bc,abc,null
  • 暴力穷举

打印字符串的全部排列

思路

  • 全排列,先前所选用的字符,后面后不可以选择了。

代码

package class08;import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;public class Code03_PrintAllPermutations {public static ArrayList<String> Permutation(String str) {ArrayList<String> res = new ArrayList<>();if (str == null || str.length() == 0) {return res;}char[] chs = str.toCharArray();process(chs, 0, res);return res;}// str[i..]范围上,所有的字符,都可以在i位置上,后续都去尝试// str[0..i-1]范围上,是之前做的选择// 请把所有的字符串形成的全排列,加入到res里去public static void process(char[] str, int i, ArrayList<String> res) {if (i == str.length) {res.add(String.valueOf(str));}boolean[] visit = new boolean[26]; // visit[0 1 .. 25]for (int j = i; j < str.length; j++) {if (!visit[str[j] - 'a']) {visit[str[j] - 'a'] = true;swap(str, i, j);process(str, i + 1, res);swap(str, i, j);}}}public static void swap(char[] chs, int i, int j) {char tmp = chs[i];chs[i] = chs[j];chs[j] = tmp;}public static List<String> getAllC(String s) {List<String> ans = new ArrayList<>();ArrayList<Character> set = new ArrayList<>();for (char cha : s.toCharArray()) {set.add(cha);}process(set, "", ans);return ans;}public static void process(ArrayList<Character> list, String path, List<String> ans) {if (list.isEmpty()) {ans.add(path);return;}HashSet<Character> picks = new HashSet<>();//set中每一个字符,都可以作为当前字符,但是一旦当前决定要,后续就不能再次使用了 (去重)for (int index = 0; index < list.size(); index++) {if (!picks.contains(list.get(index))) {picks.add(list.get(index));String pick = path + list.get(index);ArrayList<Character> next = new ArrayList<>(list);next.remove(index);process(next, pick, ans);}}}public static void main(String[] args) {String s = "aac";List<String> ans = getAllC(s);for (String str : ans) {System.out.println(str);}}}

数字转化

题目要求

思路 

  • 输入原始的字符串111,下面012对应其位置,对于第i个节点,i可以自己实现转化,或者连带i+1实现转化

  • 但是需要判定i和i+1是否超出26,因为26最大代表z

  • 遇到0的时候,要判定:比如“102”,如果1自己单独做决定,那么0自己不可以做决定,0和2也不可以做决定,因此0只可以和且在一起,才是有效的

代码

package class08;public class Code06_ConvertToLetterString {public static int number(String str) {if (str == null || str.length() == 0) {return 0;}return process(str.toCharArray(), 0);}// i之前的位置,如何转化已经做过决定了, 不用再关心// str[i... ] 有多少种转化的结果public static int process(char[] str, int i) {if (i == str.length) { // base case//来到终止的位置,之前的路径代表一种有效的方法return 1;}// i没有到终止位置if (str[i] == '0') {//“102”的情形,0做不了决定return 0;}// str[i]字符不是‘0’if (str[i] == '1') {int res = process(str, i + 1); // i自己作为单独的部分,后续有多少种方法if (i + 1 < str.length) {res += process(str, i + 2); // (i和i+1)作为单独的部分,后续有多少种方法}return res;}if (str[i] == '2') {int res = process(str, i + 1); // i自己作为单独的部分,后续有多少种方法// (i和i+1)作为单独的部分并且没有超过26,后续有多少种方法if (i + 1 < str.length && (str[i + 1] >= '0' && str[i + 1] <= '6')) {res += process(str, i + 2); // (i和i+1)作为单独的部分,后续有多少种方法}return res;}// str[i] == '3' ~ '9'return process(str, i + 1);}public static int dpWays(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') {dp[i] = 0;} else if (str[i] == '1') {dp[i] = dp[i + 1];if (i + 1 < N) {dp[i] += dp[i + 2];}} else if (str[i] == '2') {dp[i] = dp[i + 1]; if (i + 1 < str.length && (str[i + 1] >= '0' && str[i + 1] <= '6')) {dp[i] += dp[i + 2];}} else {dp[i] = dp[i + 1];}}return dp[0];}public static void main(String[] args) {System.out.println(number("11111"));}}

背包问题

题目要求

代码

package class08;public class Code07_Knapsack {public static int getMaxValue(int[] w, int[] v, int bag) {return process(w, v, 0, 0, bag);}// index   当前货物的货物号//w【index】当前货物的重量//v【index】当前货物的价值//alreadyW:0至index-1已经做出的决定,所形成的目前的重量//bag:袋子的总共重量(固定参数)//index。。。后续所有货物的自由选择,返回最大的价值public static int process(int[] w, int[] v, int index, int alreadyW, int bag) {if (alreadyW > bag) {//超重了return -1;}// 重量没超if (index == w.length) {return 0;}int p1 = process(w, v, index + 1, alreadyW, bag);//不要当前index货物,获得的最大价值int p2next = process(w, v, index + 1, alreadyW + w[index], bag);//要当前货物,当前货物的价值 + 后续得到的价值int p2 = -1;if (p2next != -1) {p2 = v[index] + p2next;}return Math.max(p1, p2);}public static int maxValue(int[] w, int[] v, int bag) {return process(w, v, 0, bag);}// 只剩下rest的空间了,// index...货物自由选择,但是不要超过rest的空间// 返回能够获得的最大价值public static int process(int[] w, int[] v, int index, int rest) {if (rest <= 0) { // base case 1return 0;}// rest >=0if (index == w.length) { // base case 2return 0;}// 有货也有空间int p1 = process(w, v, index + 1, rest);int p2 = Integer.MIN_VALUE;if (rest >= w[index]) {p2 = v[index] + process(w, v, index + 1, rest - w[index]);}return Math.max(p1, p2);}public static int dpWay(int[] w, int[] v, int bag) {int N = w.length;int[][] dp = new int[N + 1][bag + 1];for (int index = N - 1; index >= 0; index--) {for (int rest = 1; rest <= bag; rest++) {dp[index][rest] = dp[index + 1][rest];if (rest >= w[index]) {dp[index][rest] = Math.max(dp[index][rest], v[index] + dp[index + 1][rest - w[index]]);}}}return dp[0][bag];}public static void main(String[] args) {int[] weights = { 3, 2, 4, 7 };int[] values = { 5, 6, 3, 19 };int bag = 11;System.out.println(maxValue(weights, values, bag));System.out.println(dpWay(weights, values, bag));}}

取牌

思路

  • 第一种情形,只剩下一张牌的时候,直接取最后一张牌就可以了

  • 如果取最左边的牌,计算我的成绩为arr【L】+S(arr,L+1,R)

  • 如果取最右边的牌,计算我的成绩为arr【R】+S(arr,L,R-1)

  • 对于上面两种情形取最大值就是我的选择

  • 其中S为黑盒函数,因为先手和后手是互换的角色,当先手取完牌之后,其角色就变成后手了

代码

package class08;public class Code08_CardsInLine {public static int win1(int[] arr) {if (arr == null || arr.length == 0) {return 0;}return Math.max(f(arr, 0, arr.length - 1), s(arr, 0, arr.length - 1));}public static int f(int[] arr, int i, int j) {if (i == j) {return arr[i];}return Math.max(arr[i] + s(arr, i + 1, j), arr[j] + s(arr, i, j - 1));}public static int s(int[] arr, int i, int j) {if (i == j) {return 0;//后手没有牌可以拿}return Math.min(f(arr, i + 1, j), f(arr, i, j - 1));//要让对方拿最小的值}public static int win2(int[] arr) {if (arr == null || arr.length == 0) {return 0;}int[][] f = new int[arr.length][arr.length];int[][] s = new int[arr.length][arr.length];for (int j = 0; j < arr.length; j++) {f[j][j] = arr[j];for (int i = j - 1; i >= 0; i--) {f[i][j] = Math.max(arr[i] + s[i + 1][j], arr[j] + s[i][j - 1]);s[i][j] = Math.min(f[i + 1][j], f[i][j - 1]);}}return Math.max(f[0][arr.length - 1], s[0][arr.length - 1]);}public static void main(String[] args) {int[] arr = { 1, 9, 1 };System.out.println(win1(arr));System.out.println(win2(arr));}}

N皇后问题

思路

  • 假设先前一个皇后的位置是(a,b),那么再次摆一个皇后的位置是(c,d),因为是从上往下执行,因此可以保证每个皇后之间不共行

  • 通过比对b和d判定皇后之间是否共列

  • 通过比对|c-a|==|d-b|来判定是否处于一个斜线上

代码

package class08;public class Code09_NQueens {public static int num1(int n) {if (n < 1) {return 0;}// record[0] ?  record[1]  ?  record[2]int[] record = new int[n]; // record[i] -> i行的皇后,放在了第几列return process1(0, record, n);}// 潜台词:record[0..i-1]的皇后,任何两个皇后一定都不共行、不共列,不共斜线// 目前来到了第i行// record[0..i-1]表示之前的行,放了的皇后位置// n代表整体一共有多少行// 返回值是,摆完所有的皇后,合理的摆法有多少种public static int process1(int i, int[] record, int n) {if (i == n) { // 终止行return 1;}int res = 0;for (int j = 0; j < n; j++) { // 当前行在i行,尝试i行所有的列  -> j// 当前i行的皇后,放在j列,会不会和之前(0..i-1)的皇后,不共行共列或者共斜线,// 如果是,认为有效// 如果不是,认为无效if (isValid(record, i, j)) {record[i] = j;res += process1(i + 1, record, n);}}return res;}// record[0..i-1]你需要看,record[i...]不需要看// 返回i行皇后,放在了j列,是否有效public static boolean isValid(int[] record, int i, int j) {for (int k = 0; k < i; k++) { // 之前的某个k行的皇后if (j == record[k] || Math.abs(record[k] - j) == Math.abs(i - k)) {return false;}}return true;}// 请不要超过32皇后问题,如果类型改为long,则可以计算64皇后问题public static int num2(int n) {if (n < 1 || n > 32) {//throw new RuntimeException("问题太大,难以计算");//运行错误:不用try catch 和 抛出声明//预期错误:使用try catch ,比如,将异常捕获,然后告诉使用者,输入类型出错 return 0;}int limit = n == 32 ? -1 : (1 << n) - 1;return process2(limit, 0, 0, 0);}//优化版本 递归使用、使用二进制类型计算// colLim 列的限制,1的位置不能放皇后,0的位置可以// leftDiaLim 左斜线的限制,1的位置不能放皇后,0的位置可以// rightDiaLim 右斜线的限制,1的位置不能放皇后,0的位置可以public static int process2(int limit, int colLim, int leftDiaLim,int rightDiaLim) {if (colLim == limit) { // base casereturn 1;}// 所有候选皇后的位置,都在pos上int pos = limit & (~(colLim | leftDiaLim | rightDiaLim));int mostRightOne = 0;int res = 0;while (pos != 0) {mostRightOne = pos & (~pos + 1);pos = pos - mostRightOne;res += process2(limit, colLim | mostRightOne,(leftDiaLim | mostRightOne) << 1,(rightDiaLim | mostRightOne) >>> 1);}return res;}public static void main(String[] args) {int n = 14;long start = System.currentTimeMillis();System.out.println(num2(n));long end = System.currentTimeMillis();System.out.println("cost time: " + (end - start) + "ms");start = System.currentTimeMillis();System.out.println(num1(n));end = System.currentTimeMillis();System.out.println("cost time: " + (end - start) + "ms");}
}

 

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

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

相关文章

rtsp和sdp

RTSP 是由Realnetwork 和Netscape共同提出的如何有效地在IP网络上传输流媒体数据的应用层协议 。 实时流协议&#xff08;RTSP&#xff09;建立并控制一个或几个时间同步的连续流媒体&#xff0c;如音频和视频。尽管连续媒体流与控制流交叉是可能的&#xff0c;RTSP本身并不发…

使用javascript实现对于chineseocr的API调用

ChineseOCR在线API 网页地址 界面 提供多种接口调用方式&#xff0c;比如在线调用、Javascript api调用、curl api调用和python api调用四种方式&#xff0c;本次使用javascript api调用的方式进行OCR识别在线Javascript工具 在线工具网页链接在线Base64 转化工具 在线工具…

移动流媒体业务的技术与标准

1 引言   流媒体业务是从Internet上发展起来的一种多媒体应用&#xff0c;指使用流&#xff08;Streaming&#xff09;方式在网络上传输的多媒体文件&#xff0c;包括音频、视频和动画等。   流媒体传输技术的主要特点是以流&#xff08;streaming&#xff09;的形式进行多…

使用python实现对于chineseocr的API调用

ChineseOCR在线API 网页链接 界面 提供多种接口调用方式&#xff0c;比如在线调用、Javascript api调用、curl api调用和python api调用四种方式&#xff0c;本次使用javascript api调用的方式进行OCR识别在线Base64 转化工具 Base64在线小工具代码修改 新增一个变量fill_w…

算法入门篇十 图

图的存储方式 临接表临接矩阵 表达 点集/边集有向图/无向图 Graph&#xff08;大结构就是图&#xff09;&#xff08;包含点集合和边集合&#xff09; import java.util.HashMap; import java.util.HashSet;public class Graph {public HashMap<Integer, Node> nodes;…

超文本传输协议

超文本传输协议 超文本传输协议超文件传输协定(HTTP&#xff0c;HyperTextTransfer Protocol)是因特网上应用最为广泛的一种网络传输协定。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。 目录 介绍请求信息请求方法安全方法超…

利用MFC调用libvlc.dll作一个简单的播放器

简单介绍MFC调用libvlc.dll作一个简单的播放器&#xff0c;抛砖引玉&#xff0c;各位VC达人继续深入研究&#xff0c;Jeremiah对VC确实不太感兴趣&#xff0c;所以就不做太深入的研究了。2009.10.29修改&#xff1a;加入clip_children属性设置。参开第1步。环境&#xff1a; …

使用Remix编写Solidity语言的小例子

设置数值/取数值/加法运算 讲解 uint默认使用256位数的整型view表示这个函数仅仅对于数据仅仅是读取&#xff0c;没有修改操作returns(uint )&#xff0c;如果单纯指定uint&#xff0c;返回的是函数体内的return值&#xff0c;如果包含uint sum,uint SAD_a&#xff0c;那么返…

RTP协议栈简介

流媒体指的是在网络中使用流技术传输的连续时基媒体&#xff0c;其特点是在播放前不需要下载整个文件&#xff0c;而是采用边下载边播放的方式&#xff0c;它是视频会议、IP电话等应用场合的技术基础。RTP是进行实时流媒体传输的标准协议和关键技术&#xff0c;本文介绍如何在L…

使用多线程的方式调用chineseocr_API

ChineseOCR在线API 网页链接 界面 提供多种接口调用方式&#xff0c;比如在线调用、Javascript api调用、curl api调用和python api调用四种方式&#xff0c;本次使用javascript api调用的方式进行OCR识别代码 import glob import base64 import os import requests import …

开源好代码 音视频

VirtualDub 一、简介 图1VirtualDub主界面 VirtualDub是一款开源的音视频捕获、处理软件。VirtualDub也可称为一款多媒体编辑软件&#xff0c;因为它包含了多媒体输入、编辑、处理、输出等各个环节&#xff0c;但是作者并未将它定位为一款多媒体编辑软件&#xff08;参见官网&a…

深入理解Solidity 二

Solidity数据位置 所有复杂的数据类型&#xff0c;即数组、结构和映射类型&#xff0c;都会有一个额外属性“数据位置”&#xff0c;用来指定数据的存储位置&#xff0c;即数据是存储在memory还是存储在storage里面根据上下文环境&#xff0c;IDE会自动指定数据的默认存储位置…

VOIP简介

一、什么是VOIP VOIP全称为&#xff08;VoiceOver Internet Protocol&#xff09;&#xff0c;是一种利用Internet网络进行语音通信的技术&#xff0c;更通俗一点说&#xff0c;就是IP电话。就是以IP分组交换网为传输平台&#xff0c;对模拟的语音信号进行编码压缩&#xff0c…

深入理解Solidity 三

Solidity函数声明和类型 函数的值类型有两类&#xff1a;内部&#xff08;internal&#xff09;类型和外部&#xff08;external&#xff09;类型内部函数只可以在当前合约内部被调用&#xff08;即在当前代码块内&#xff0c;包括内部库函数和继承函数&#xff09;&#xff0c…

安装solc模块4.25版本

使用国产阿里云的cnpm 如果不知道cnpm 参考链接 安装solc模块4.25版本 npm i solc0.4.25 --save -g查看安装是否成功 可以配置软连接使用solc&#xff0c;我的没有配置 solcjs --version

在pycharm中使用conda虚拟环境(conda虚拟环境是已经创建好的),解决python安装包文件很费劲的问题

查看conda的虚拟环境 使用PyCharm连接conda创建的虚拟环境&#xff0c;需要一个前提就是虚拟环境必须存在&#xff0c;使用conda env list命令查看虚拟环境列表打开PyCharm软件 打开pycharm&#xff0c;选择File->setting->Project:****->Project Interperter&#…

完成一个H.265/HEVC码流分析工具

经过大约一个月左右的业余时间&#xff0c;终于初步完成一个H.265/HEVC码流分析工具。时间包括平时的周末、晚上&#xff0c;以及调休的集中时间。当然&#xff0c;中秋回家过节不写代码。截至今天&#xff0c;经过多种H.265序列测试&#xff0c;也有各种工具对比&#xff0c;基…

Golomb及指数哥伦布编码原理介绍及实现

文章来源&#xff1a; https://www.cnblogs.com/wangguchangqing/p/6297792.html &#xff0c; 写的不错&#xff0c;转发出来。 2017年的第一篇博文。 本文主要有以下三部分内容&#xff1a; 介绍了Golomb编码&#xff0c;及其两个变种&#xff1a;Golomb-Rice和Exp-Golo…

解决ipfs 出现Error: can‘t publish while offline: pass `--allow-offline` to override的问题

原因 出现这个问题的原因是因为&#xff0c;ipfs未与公网上的节点相互连接&#xff0c;因此此时处于离线状态 使用场景 部署自己的博客&#xff0c;后期的改动&#xff0c;累计追加在同一个地址&#xff0c;这个地址是唯一的&#xff0c;也就是创建ipfs生成的ID号 步骤 1&…

安装ipfs-http-client出现constants@0.1.2 install: node build.js > index.browser.js错误的解决办法

错误截图 原先的命令 npm install --save-dev ipfs-http-client 修改后的命令 npm install --save-dev ipfs-http-client --unsafe-permtrue --allow-root