第八课.暴力递归
作者:互联网
1.汉诺塔:打印n层汉诺塔从最左边移动到最右边的全部过程
public static void hanoi(int n) {
if (n > 0) {
func(n, "左", "中", "右");
}
}
//1-i圆盘,目标是from->to,other是另外一个
public static void func(int i, String start, String end, String other) {
if (i == 1) {
System.out.println("move 1 from " + start + " to " + end);
} else {
func(i - 1, start, other, end);
System.out.println("move" + i + "from " + start + " to " + end);
func(i- 1, other, end, start);
}
}
public static void main(String[] args) {
int n = 3;
hanoi(n);
}
2.打印一个字符串的全部字序列,包括空字符串
法一:
public static void function(String str) {
char[] chars = str.toCharArray();
process(chars,0,new ArrayList<Character>());
}
//当前来到i位置,要和不要,走两条路
//res之前的选择,所形成的路
public static void process(char[] chs, int i, List<Character> res) {
if(i==chs.length){
printList(res);
return;
}
List<Character> characters1 = copyList(res);
process(chs,i+1,characters1);//要当前字符
List<Character> characters2 = copyList(res);
characters2.add(chs[i]);
process(chs,i+1,characters2);//不要当前字符
}
public static void printList(List<Character> res) {
for (Character re : res) {
System.out.print(re);
}
System.out.println("\n");
}
public static List<Character> copyList(List<Character> list){
List<Character> listA=new ArrayList<>();
for (Character character : list) {
listA.add(character);
}
return listA;
}
public static void main(String[] args) {
String test = "abc";
function(test);
}
法二:
public static void printAllSubsquence(String str) {
char[] chars = str.toCharArray();
process(chars,0);
}
//之前的选择,所形成的的结果,是str
public static void process(char[] chs, int i) {
if(i==chs.length){
System.out.println(String.valueOf(chs));
return;
}
process(chs,i+1);
char temp=chs[i];//要当前字符的路
chs[i]=0;
process(chs,i+1);//不要当前字符的路
chs[i]=temp;
}
public static void main(String[] args) {
String test = "abc";
printAllSubsquence(test);
}
3.打印一个字符串的全排列,要求不出现重复的排列
public static ArrayList<String> Permutation(String str) {
if(str==null||str.length()==0){
return null;
}
char[] chars = str.toCharArray();
ArrayList<String> res=new ArrayList<>();
process(chars,0,res);
return res;
}
//str[i..]范围上,所有的字符,都可以在i位置上,后续都去尝试
//str[0..i-1]范围上,是之前做的选择
//把所有的字符串所形成的全排列,加入到res里去
public static void process(char[] chs, int i, ArrayList<String> res) {
if(i==chs.length){
res.add(String.valueOf(chs));
return;
}
boolean visit[]= new boolean[26];
for(int j=i;j<chs.length;j++){
if(!visit[chs[j]-'a']){
visit[chs[j]-'a']=true;
swap(chs,i,j);
process(chs,j+1,res);
swap(chs,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 void main(String[] args) {
String abc="abc";
ArrayList<String> permutation = Permutation(abc);
for (String s : permutation) {
System.out.println(s);
}
}
4.给你一个栈,请逆序这个栈,不能申请额外的数据结构,只能使用递归函数
public static void reverse(Stack<Integer> stack) {
if(stack.isEmpty()){
return;
}
int result=getAndRemoveLastElement(stack);
reverse(stack);
stack.add(result);
}
public static int getAndRemoveLastElement(Stack<Integer> stack) {
int result=stack.pop();
if(!stack.isEmpty()){
int last = getAndRemoveLastElement(stack);
stack.push(result);
return last;
}else{
return result;
}
}
public static void main(String[] args) {
Stack<Integer> test = new Stack<Integer>();
test.push(1);
test.push(2);
test.push(3);
test.push(4);
test.push(5);
reverse(test);
while (!test.isEmpty()) {
System.out.println(test.pop());
}
}
5.规定1和A对应,2和B对应,3和C对应
一个数字字符比如‘111’,就可以转化为“AAA”,“KA”和“AK”。
给定一个只有数字字符组成的字符串str,返回有多少种转化的结果
public static int number(String str) {
if(str==null||str.length()==0){
return 0;
}
return process(str.toCharArray(),0);
}
//i之前的位置,如何转化已经做过决定了
//i...有多少种转化的结果
public static int process(char[] chs, int i) {
if(i==chs.length){
return 1;
}
if(chs[i]=='0'){
return 0;
}
if(chs[i]=='1'){//i自己作为单独的部分,后续有多少种方法
int res =process(chs,i+1);
if(i+1<chs.length){
res+=process(chs,i+2);//(i和i+1)作为单独的部分,后续有多少种方法
}
return res;
}
if(chs[i]=='2'){
int res=process(chs,i+1);//i自己作为单独的部分,后续有多少种方法
if (i + 1 < chs.length && chs[i+1]<='6'&&chs[i+1]>='0') {
res+=process(chs,i+2);//(i和i+1)作为单独的部分并且没有超过26,后续有多少种方法
}
return res;
}
return process(chs,i+1);
}
6.给定两个数组w和v,两个数组长度相等,w[i]表示第i件商品的重量,v[i]表示第i件商品的价值。再给定一个数组bag,要求你挑选商品的重量一定不能超过bag,返回满足这个条件下,你能获得的最大价值。
法一:有alreadyValue
public static int maxValue1(int[] weights, int[] values, int bag) {
return process2(weights, values, 0, 0, 0,bag);
}
public static int process2(int[] weights, int[] values, int i, int alreadyweight, int alreadyValue, int bag) {
if(alreadyweight>bag){
return 0;
}
if(i==weights.length){
return alreadyValue;
}
return Math.max(process2(weights,values,i+1,alreadyweight+weights[i],alreadyValue+values[i],bag),process2(weights,values,i+1,alreadyweight,alreadyValue,bag));
}
法二:没有alreadyValue
public static int maxValue1(int[] weights, int[] values, int bag) {
return process1(weights, values, 0, 0, bag);
}
//i..的货物自由选择,形成的最大价值返回
//重量永远不要超过bag
//之前做的决定,所达到的重量,alreadyweight
public static int process1(int[] weights, int[] values, int i, int alreadyweight, int bag) {
if (alreadyweight > bag) {
return 0;
}
if (i == weights.length) {
return 0;
}
return Math.max(
process1(weights, values, i + 1, alreadyweight, bag),
values[i] + process1(weights, values, i + 1, alreadyweight + weights[i], bag));
}
测试代码:
public static int maxValue2(int[] c, int[] p, int bag) {
int[][] dp = new int[c.length + 1][bag + 1];
for (int i = c.length - 1; i >= 0; i--) {
for (int j = bag; j >= 0; j--) {
dp[i][j] = dp[i + 1][j];
if (j + c[i] <= bag) {
dp[i][j] = Math.max(dp[i][j], p[i] + dp[i + 1][j + c[i]]);
}
}
}
return dp[0][0];
}
public static void main(String[] args) {
int[] weights = { 3, 2, 4, 7 };
int[] values = { 5, 6, 3, 19 };
int bag = 11;
System.out.println(maxValue1(weights, values, bag));
System.out.println(maxValue2(weights, values, bag));
}
7.给定一个整型数组arr,代表数值不同的纸牌排成一条线。玩家A和玩家B依次拿走每张纸牌,规定玩家A先拿,玩家B后拿。但是每个玩家每次只能拿走最左或最右的纸牌,玩家A和玩家B都绝顶聪明。请返回最后获胜者的分数。
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));//注意调用的是s
}
//后手
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));//注意调用的是f,并且没有arr[i]+
}
测试:
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));
}
8.N皇后问题:
法一:正规解法
public static int num1(int n) {//n个皇后
if (n < 1) {
return 0;
}
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;
}
法二:位运算优化(没有掌握)
public static int num2(int n) {
if (n < 1 || n > 32) {
return 0;
}
int upperLim = n == 32 ? -1 : (1 << n) - 1;
return process2(upperLim, 0, 0, 0);
}
public static int process2(int upperLim, int colLim, int leftDiaLim,
int rightDiaLim) {
if (colLim == upperLim) {
return 1;
}
int pos = 0;
int mostRightOne = 0;
pos = upperLim & (~(colLim | leftDiaLim | rightDiaLim));
int res = 0;
while (pos != 0) {
mostRightOne = pos & (~pos + 1);
pos = pos - mostRightOne;
res += process2(upperLim, 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");
}
标签:arr,return,暴力,递归,int,第八课,chs,static,public 来源: https://blog.csdn.net/zhiyongbo/article/details/115109441