左神第八課之遞迴演算法
題目一
求n!
簡單得不想說
題目二
漢諾塔問題
古代有一個梵塔,塔內有三個座A、B、C,A座上有64個盤子,盤子大小不等,大的在下,小的在上(如圖)。有一個和尚想把這64個盤子從A座移到C座,但每次只能允許移動一個盤子,並且在移動過程中,3個座上的盤子始終保持大盤在下,小盤在上。在移動過程中可以利用B座,要求輸出移動的步驟 。
解答
把A上的盤子編號1,2,3,4(最大的),現在把4移到C只要1,2,3到B再把4移動到C,在把1,2,3移動到C
當搬運的碟子數n=1時,直接搬運即可;當n>1時,要把n個碟子從針1搬運到針3,則必須通過針2(即需要一個獨立於源針和目的針的中間針,用來輔助);假設我們已經成功的把上面較小的n-1個碟子搬運到了針2,那麼我們只需要再把第n個碟子(底層最大的那個)搬運到針3,再把針2的n-1個碟子搬運到針3,那麼這n個碟子塔就成功的搬運到了針3了.而整個n-1的塔要怎麼搬運呢?這就是遞迴啦
所以整個步驟:
1.搬運n-1個碟子到中間針(遞迴)
2.搬運第n個碟子到目的針
3.搬運中間針的n-1個碟子到目的針(遞迴)
void move (getone,putone)
函式的作用是用於搬運最底層的第n個碟子,從getone針搬到putone針
void hanoi (n,one,two,three)
函式的作用是,把n層塔從one針(源)搬運到three針(目的),用two針來輔助(中間)
所以上面的步驟就可以翻譯成c語言了
要想把n個碟子從one針搬運到three針的三個步驟:
(與第一段陳述的三個步驟對應,即hanoi(n,one,two,three)函式要完成的功能,函式主體)
1.hanoi(n-1,one,three,two);是遞迴呼叫,如果n-1>1則它又會去執行3個步驟,以至於無窮
2.move(one,three);這一步是具體移動,所以要輸出移動方法,讓使用者能看見移動方向
3.hanoi(n-1,two,one,three);遞迴
遞迴呼叫只要有整體觀念就行了,你在寫程式碼的過程中可以把”移動n-1個塔”看作一步完成的,至於這步是怎麼完成的,會由計算機逐級遞迴展開函式棧具體實現,我們不必多想.因為每一級的過程都是一樣的,所以用遞迴,減少程式碼規模
遞迴的思想相對較容易,即只看見本層次,低層次由於過程和本層完全相同,呼叫遞迴函式自身,來重複利用程式碼.由於會函式巢狀呼叫會有多餘的時間空間耗費,所以在遞迴次數過大等情況下,儘量用非遞迴的方法實現.
程式碼如下
public class Code_02_Hanoi {
static int b=0;
public static void hanoi(int n,String from, String help, String to) {
if (n ==1) {
System.out.printf("%d號盤:%s-->%s\n",n,from,to);
b++;
}else{
hanoi(n-1, from, to, help);
System.out .printf("%d號盤:%s-->%s\n",n ,from,to);
hanoi(n-1, help, from, to);
b++;
}
}
public static void main(String[] args) {
int n = 4;
hanoi(n, "A", "B", "C");
System.out.println(b);
}
}
題目四
列印一個字串的全部排列
import java.util.LinkedList;
import java.util.List;
public class Code_03_Print_All_Subsquences {
public static List<List<Character>> ans = new LinkedList<List<Character>>();
public static LinkedList<Character> list = new LinkedList<Character>();
public static void printAllSubsquence(String str) {
char[] chs = str.toCharArray();
process(chs, 0);
}
private static void process(char[] chs, int index) {
if (index >= chs.length ) {
LinkedList<Character> list2 = new LinkedList<Character>();
list2.addAll(list);
ans.add(list2);
return;
}
list.add(chs[index]);
process(chs, index + 1);
list.pollLast();
process(chs, index + 1);
}
public static void main(String[] args) {
printAllSubsquence("123");
System.out.println(ans);
}
}
題目五
列印一個數字的全排列
package lesson8;
import java.util.LinkedList;
import java.util.List;
public class Code_04_Print_All_Permutations {
public static List<List<Integer>> ans = new LinkedList<List<Integer>>();
public static boolean[] v = new boolean[100];
public static LinkedList<Integer> list = new LinkedList<Integer>();
public static void robot(int index, int[] nums) {
if (index >= nums.length) {
List<Integer> list2 = new LinkedList<Integer>();
list2.addAll(list);
ans.add(list2);
return;
}
for (int i = 0; i < nums.length; i++) {
if (v[i] == false) {
v[i] = true;
list.add(nums[i]);
robot(index + 1, nums);
list.pollLast();
v[i] = false;
}
}
}
public static void main(String[] args) {
int[] arr = { 1, 2, 3 };
robot(0, arr);
System.out.println(ans);
}
}
題目六
母牛每年生一隻母牛,新出生的母牛成長三年後也能每年生一隻母牛,假設不會死。求N年後,母牛的數量。
public class Code_05_Cow {
public static int cowNumber1(int n) {
if (n < 1) {
return 0;
}
if (n == 1 || n == 2 || n == 3) {
return n;
}
return cowNumber1(n - 1) + cowNumber1(n - 3);
}
public static int cowNumber2(int n) {
if (n < 1) {
return 0;
}
if (n == 1 || n == 2 || n == 3) {
return n;
}
int res = 3;
int pre = 2;
int prepre = 1;
int tmp1 = 0;
int tmp2 = 0;
for (int i = 4; i <= n; i++) {
tmp1 = res;
tmp2 = pre;
res = res + prepre;
pre = tmp1;
prepre = tmp2;
}
return res;
}
public static void main(String[] args) {
int n = 20;
System.out.println(cowNumber1(n));
System.out.println(cowNumber2(n));
}
}
題目七
給你一個棧,請你逆序這個棧,不能申請額外的資料結構,只能使用遞迴函式。如何實現?
import java.util.Stack;
public class Code_06_ReverseStackUsingRecursive {
public static int process(Stack<Integer> s) {
int a = s.pop();
if (s.isEmpty()) {
return a;
}
int b = process(s);
s.push(a);
return b;
}
public static void reverse(Stack<Integer> s, int n, int size) {
if (n == size) {
return;
}
int a = process(s);
reverse(s, n + 1, size);
s.push(a);
}
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, 0, test.size());
System.out.println(test);
}
}
題目八
給你一個二維陣列,二維陣列中的每個數都是正數,要求從左上角走到右下角,每一步只能向右或者向下。沿途經過的數字要累加起來。返回最小的路徑和。
解答
動態規劃
題目九
給你一個數組arr,和一個整數aim。如果可以任意選擇arr中的數字,能不能累加得到aim,返回true或者false
題目十
給定兩個陣列w和v,兩個陣列長度相等,w[i]表示第i件商品的重量,v[i]表示第i件商品的價值。 再給定一個整數bag,要求你挑選商品的重量加起來一定不能超 過bag,返回滿足這個條件下,你能獲得的最大價值。