前言
- 思想:二分思想,舍棄思想,遞歸樹思想,
- 重點:數軸,樹思想,棧思想,二分,多分思想,master公式
- 一遇遞歸,直接造樹!!
- 遞歸,永遠不要把它當作一個方法,你可以把它當作一個過程樹
先想想遞歸最大值:
-
1.[L,R]上求最大值
- 定:遞歸求最大,數軸,拆分為樹
- 解:
- 1.二分思想,兩個跑肯定比單個跑快--那么就涉及到中間,中間數的求法最好就是舍棄法
- 2.中間為分界,左邊跑,右邊跑
- 3.調用Math函數進行比較
- 思維解:
- 1.多叉樹,2.利用棧后繼遍歷.3.懸而未決壓入棧 4.清晰的就出去 5.高度上壓棧
- 懸而未決(有的孩子(子節點)不知道是多少)
- 棧彈出,遇到我們的判斷出遞歸條件
- 1.多叉樹,2.利用棧后繼遍歷.3.懸而未決壓入棧 4.清晰的就出去 5.高度上壓棧
- 規范:只有一個數?直接處理
- 注:Math雖然好用,但只能用於判斷回值.數據的交換,還是需交換方式,
-
舍棄法(關於舍棄,很大的表現就是有效增益--可看力扣53.最大子序和)
-
求最大
-
使用樹的方式,將我們要求的因子找出來,減少普通排序的一次次比較
-
2.遞歸的master公式---(重點)
- 定:遞歸的復雜度,遞歸的執行流程
- 解:
- 1.先樹,棧的形式解析整個遞歸 ---發現樹的高度就是遞歸的次數
- 2.master公式的學習
- T(N)=a*(N/b)+O(N^d)
- 主方法 = 次數*子方法+其它 --- 遞歸的主方法和子方法也就參數不一樣
- a指的是調用方法次數,b指的是切割問題幾段,,N指的是復雜度
- 3.時間復雜度的計算
- 1.log(b,a)>d--->復雜度O(N^log(b,a))
- 2.log(b,a)
復雜度O(N^d) - 3.log(b,a)==d--->復雜度O(O^d * logN)
-
一般使用遞歸是為了職責分明,遞歸就進棧,彈棧就好了,彈棧是由自己寫的條件控制.有多子遞歸時,那就樹來走
歸並
本質:二分排序,再合並
- 歸並的做法是:左側比較完,右側比較完,再最后左右比較
- 還是兩兩交換,,不管是for循環,還是遞歸---兩者都是使用二分思想來變成O(logN),本質是讓兩個數兩兩交互排序
歸並遞歸法
- 我測試了它的遞歸走向
- 發現它的走向是按照(終止條件,方法體控制的),遞歸的本質是都走
- 怎么走,就是如果里面是雙子遞歸,那么它會按樹走,走的時候,是先左大節點,再左大節點的左子節點,再左大節點的右子節點.(往復進行),中途走到終止條件跳出,
其它繼續執行,,遇到很小的滿足要求方法體的也會去執行.
- 它的目的就是,整個流程我都整出來並且壓入棧,執行完的或者遇到條件的就出去,按照你的控制停止,你有條件,滿足就執行.
必須明白的遞歸彈棧
-
數組為{11,8,9,4,12,3,7,6}--[0,7]
-
開始,進棧[0,7],遇到子,再進棧[0,3],遇到子,再進棧[0,1],再遇到再進,直到遇到該停止的,再不斷的彈,彈出這一步,走下一步,下一步再彈,再...
-
簡單沒有彈,只是順序執行的流程
這是一個,沒有終止彈棧的流程 原數據:11,8,9,4,12,3,7,6 遞歸流程:0--1 方法執行:8 11 遞歸流程:2--3 方法執行:4 9 遞歸流程:0--3 方法執行:4 8 9 11 遞歸流程:4--5 方法執行:3 12 遞歸流程:6--7 方法執行:6 7 遞歸流程:4--7 方法執行:3 6 7 12 遞歸流程:0--7 方法執行:3 4 6 7 8 9 11 12 輸出結果:3 4 6 7 8 9 11 12
-
歸並排序代碼:
public class MergeSortTest { // 解---由大到小解決, // 1.解遞歸 // 0,R都是數組下標 public void process(int arr[],int L,int R){ if(L==R){ // 結束標志,也就是葉子節點結束 return; } int m = L+((R-L)>>1); process(arr,L,m); //----L----m-----R-- 不僅僅一個,是樹 process(arr,m+1,R); /* System.out.println("遞歸流程"+":"+L + "--" + R);*/ merge(arr,L,m,R); } // 2.解排序--按照最基本的葉子進行計算,滿足最基本的LMR的葉子進行思考,如 529 public void merge(int arr[],int L,int M,int R){ // 定:要使得兩邊有序 --- // 解:最基本的葉子,529--- // 需求:指針,[L,M]邊的,[M,R]邊的 int p1 = L; int p2 = M+1; // 輔助數組存值 int help[] = new int[R-L+1]; int i = 0; // 輔助的指針 // 節點卡標 while (p1 <= M && p2 <= R){ // 有一個指針滿足就停止 help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++]; // 此時必定會將一邊的全打進去 } while (p1 <= M){ help[i++] = arr[p1++]; } while (p2 <= R){ help[i++] = arr[p2++]; } for (int j = 0; j < help.length; j++) { arr[L+j] = help[j]; } /* // merge方法體流程! System.out.print("方法執行:"); for (int i1 : help) { System.out.print(i1+" "); } System.out.println(); */ } public static void main(String[] args) { MergeSortTest mergeSortTest = new MergeSortTest(); int arr[] = new int[]{11,8,9,4,12,3,7,6}; System.out.println("原數據:"+ "11,8,9,4,12,3,7,6"); mergeSortTest.process(arr,0,arr.length-1); System.out.print("輸出結果:"); for (int i : arr) { System.out.print(i+" "); } } }
BS:
- 本人目前也是在算法的路上不斷探索中,試圖和數據結構以及幾何進行掛鈎的學習,沒有圖形的算法是沒有靈魂的!
- 文章中可能有很多不對的地方,希望能多多指教,評論;博主在此感謝!