遞歸
什麼是遞歸? 直接或間接的調用自身的算法稱為遞歸算法,打趣的來說 就是 “自己玩自己”。既然遞歸是一個反複調用自身的過程,這就說明它每一級的功能都是一樣的,是以隻需關注一級遞歸的解決過程即可。
從 bokeyuan部落客 三年一夢的總結中,解遞歸題的三部曲:
1,找整個遞歸的終止條件:遞歸應該在什麼時候結束?
2, 找傳回值:應該給上一級傳回什麼資訊?
3,本級遞歸應該做什麼:在這一級遞歸中,應該完成什麼任務?
疊代
疊代是利用變量的原值推算出變量的一個新值,如果遞歸是自己調用自己的話,疊代就是A不停的調用B。也就是,遞歸是自己玩自己,疊代是自己玩别人。
遞歸經典例題
例1: n的階乘
package com.company;
import java.math.BigInteger;
import java.util.Scanner;
public class N_ {
public static void main(String[] args) {
System.out.println("求數字幾的階乘啊?");
Scanner a = new Scanner(System.in);
int b = a.nextInt();
System.out.println(ade(b));
}
public static long ade(long c) {
if (c <= 0) {
return 0;
} else if (c == 1) {
return 1;
} else return c * ade(c - 1);
}
}
對代碼加入了scanner,可以擷取任意數的階乘,需要注意的是 int可表示範圍, 在java中,int 最多到12的階乘,long最多到20,BigInteger随意精度,運算符應用受限(暫時還不會用)。
例2:斐波納切數列
package com.company;
import java.util.Scanner;
public class factorial {
public static void main(String[] args) {
System.out.println("請輸入n:");
Scanner a = new Scanner(System.in);
String b = a.next();
int c = Integer.parseInt(b);
System.out.println(func(c));
}
public static int func(int n) {
if (n < 0) {
return 0;
} else if (n == 1) {
return 1;
} else {
return n * func(n - 1);
}
}
}
例3: 漢諾塔問題
(1) 最後盤子都放在B上
package com.company;
import java.util.Scanner;
public class Hnaoi{
static int times;
public static void main(String[] args) {
char A = 'A';
char B = 'B';
char C = 'C';
Scanner q = new Scanner(System.in);
System.out.println("請輸入盤子數:");
int n = q.nextInt();
hno(n,A,B,C);
}
public static void move(int Disk, char M,char N){
System.out.println("第"+(++times)+"次移動,盤子" +Disk+" " +M +"到"+N);
}
public static void hno(int n,char A,char B,char C){
if( n == 1){
move(1,A,B);
}else {
hno(n-1,A,C,B);
move(n,A,B);
hno(n-1,C,B,A);
}
}
}
(2) 盤子全部放C上
public class Hnaoi {
static int times;
public static void main(String[] args) {
char A = 'A';
char B = 'C';
char C = 'B';
System.out.println("漢諾塔遊戲開始!!");
System.out.println("請輸入盤子數:");
Scanner s = new Scanner(System.in);
int n = s.nextInt();
hna(n,A,B,C);
}
public static void move(int disk,char M,char N){
System.out.println("第" +(++times)+ "次移動. 盤子" + disk +" "+ M+ "--->" +N);
}
public static void hna(int n,char A,char B,char C){
if (n == 1){
move(n,A,C);
}else {
//移動上一關的步驟到B
hna(n-1,A,C,B);
//吧最大盤子移動到C
move(n,A,C);
//再把c上上一關移動的盤子放到b上就可以了
hna(n-1,B,A,C); //B --C
}
}
}
例4: 搜尋二叉樹深度
public class BinaryTreeDepth {
ic static int getTreeDepth(Tree t) {
// 樹為空
if (t == null) // 遞歸終止條件
return 0;
int left = getTreeDepth(t.left); // 遞歸求左子樹深度,縮小問題的規模
int right = getTreeDepth(t.left); // 遞歸求右子樹深度,縮小問題的規模
return left > right ? left + 1 : right + 1;
}
}
上述例題均為遞歸算法入門題,後續要在Leetcode多做幾道遞歸題,加深了解。
leetcode.344.反轉字元串(困難等級:簡單)。
題目:編寫一個函數,其作用是将輸入的字元串反轉過來。輸入字元串以字元數組 char[] 的形式給出。不要給另外的數組配置設定額外的空間,你必須原地修改輸入數組、使用 O(1) 的額外空間解決這一問題。你可以假設數組中的所有字元都是 ASCII 碼表中的可列印字元。
public void res(char[] s) {
trs(s, 0, s.length-1);
}
public void trs(char[] s, int start, int end) {
if(start > end)
return;
trs(s, start+1, end-1);
char temp = s[start];
s[start] = s[end];
s[end] = temp;
}