關於遞歸
關於遞歸的理解:
/**
* 關於遞歸的實際理解
* @author Viaxiz
*/
public class Dugui2 {
public static void f(int n) {
if(n>0) {
f(n-1);
System.out.print(n+" ");
f(n-1);
}
}
//遞歸就是把自己當作語句調用,所以爲了完成語句的執行,其後面必然會出來的,
//想想棧的原理,先進後出,最開始調用的方法即最後一次執行的方法
//因爲執行遞歸語句後還要執行遞歸語句剩下的
public static void main(String[] args) {
f(3);
}
}
先猜猜輸出是什麼吧
1 2 1 3 1 2 1
推薦嗶哩嗶哩上的陳越姥姥講浙大數據結構
陳越姥姥講遞歸:
- 重點:
- 出口在哪
- 遞推性(相似性)
a. 相似而規模逐漸變小,以參數體現
b. 若沒有明顯的相似性,就需要主動構造
a) 關於遞歸,記得從最開始先一步一步地推,找出其中的規律(關係)
例如:
漢諾塔
黑白球
以及常見的:
輸出逆序字符串
整數劃分
遞歸的常見形式
- 尾遞歸
- 非尾遞歸
關於遞歸總給我以下感覺:
- 找規律
- 判定條件;
a. return
b.注意兩個或多個變量值傳入,其中的有些值是要相應變化的
遞歸的簡單應用:
用來生成一個數組的全排列,這個怎麼寫呢?數重for循環是不是太難寫了點了,所以想想用遞歸試試吧,當然在C++中有std :: next_permutation方法可用,不過這裏我們用Java來寫一個生成0-9之間所有數字的全排列數組吧
/**
* 生成全排列的數組,並輸出生成的全排列數組
*
* @author ASUS
*
*/
public class Permutaition {
public static int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
public static int ans = 0;
public static void main(String[] args) {
range(a, 0, a.length - 1);
if (10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 == ans)//我只是確認一下全排列的數組有多少種
System.out.println(true);
}
public static void range(int[] arr, int start, int end) {
if (start == end) {
// write(arr)輸出生成的全排列數組元素
System.out.println(
"" + arr[0] + arr[1] + arr[2] + arr[3] + arr[4] + arr[5] + arr[6] + arr[7] + arr[8] + arr[9]);
ans++;
return; // 無返回值,只是起到退出的作用
}
// 核心代碼
for (int i = start; i <= end; i++) {
swap(arr, i, start);
range(arr, start + 1, end);
swap(arr, i, start); // 沒看懂啊=…=
}
}
// 將元素交換
public static void swap(int[] arr, int x, int y) {
int tmp = arr[x];
arr[x] = arr[y];
arr[y] = tmp;
}
}
深搜(DFS)
深搜最重要的就是正確表示狀態
如,部分和的問題:
部分和的這個問題……我沒寫出來…,看下老師給的參考代碼:
李白打酒這題…也太…那啥了~
代碼示例:
關於六角形的問題,哈哈哈哈哈哈哈哈哈哈哈~,全排列大法好啊!!!一次過。
但是我們也還是看看深搜的解法吧
核心代碼:
關於深搜和廣搜:
深搜是用遞歸來實現的,其好像棧一樣
廣搜主要使用隊列來實現的,先進先出的原則
附:
簡單理解,廣搜和暴力有啥區別啊?多了隊列和剪枝??
暴力枚舉,搜索狀態。
深搜在判斷不是最終結果後,其執行的其實是接下來的狀態語句
如,接下來的狀態用循環表示;
常見的深搜模型如下
以及不用循環表示的情況:
關於遞推:
參考鏈接
當n=1:
當n=2:有7種走法,也就是綠色線條的數量
當n=3:
同樣的道理,至於兩個點的,我們只需要將減去三個點的即得到兩個點的情況了。
所以得到遞推的關係式爲:
關於Java中的容器
順勢感嘆一波這段時間過得太快了啊,從開年到現在,從準備完藍橋杯到現在,時間真的好快好快啊!少年回頭看,笑我還不快跟上!!!