#二分、二叉樹# 一節左神公開課的題解
題目1:二分查詢區域性最小值
Description:
定義區域性最小的概念。arr 長度為1時,arr[0] 是區域性最小。arr的長度為 N(N > 1) 時,如果 arr[0] < arr[1],那麼 arr[0] 是區域性最小;如果 arr[N-1] < arr[N-2],那麼 arr[N-1] 是區域性最小;如果 0 < i< N-1,既有 arr[i] < arr[i-1],又有 arr[i] < arr[i+1],那麼 arr[i] 是區域性最小。
給定無序陣列 arr,已知 arr 中任意兩個相鄰的數都不相等。寫一個函式,只需返回 arr中任意一個區域性最小出現的位置即可。
Solution:
雖然是個無序陣列,但是由於任意兩個相鄰元素的值不重複的性質決定了可以使用二分搜尋演算法。
1. 陣列為空或長度為0,返回-1,表示區域性值不存在
2. 陣列長度為1,返回位置0
3. 陣列長度大於1時:考慮三種情況
考慮最左邊和最右邊的元素:如果 arr[0] < arr[1],則 arr[0] 為區域性最小值; 如果 arr[N-1] < arr[N-2],則 arr[N-1] 為區域性最小值 考慮最中間元素:如果中間元素大於它左邊的元素,那麼區域性最小值就應該在陣列的左半部分,反之,那麼區域性最小值就應該在陣列的右半部分,如果中間元素既小於它左邊的值又小於它右邊的值,那麼它就是區域性最小
總結:
二分不一定只適用於有序陣列,只要存在一邊一定有或者一邊可能有另一邊一定沒有的情況下(即可以淘汰其中一邊)都可以使用二分
Code:
public static int getLessIndex(int[] arr) { if (arr == null || arr.length == 0) { return -1; // no exist } if (arr.length == 1 || arr[0] < arr[1]) { return 0; } if (arr[arr.length - 1] < arr[arr.length - 2]) { return arr.length - 1; } int left = 1; int right = arr.length - 2; int mid = 0; while (left < right) { mid = (left + right) / 2; if (arr[mid] > arr[mid - 1]) { right = mid - 1; } else if (arr[mid] > arr[mid + 1]) { left = mid + 1; } else { return mid; } } return left; }
題目2:輔助陣列
Description:
已知一個整型陣列arr,陣列長度為size且size大於2,arr有size-1種可以劃分成左右兩部分的方案。
比如:arr = {3, 2, 3, 4, 1, 2}
第1種劃分左部分為[3],右部分為[2, 3, 4, 1, 2]
第2種劃分左部分為[3, 2],右部分為[3, 4, 1, 2]
第3種劃分左部分為[3, 2, 3],右部分為[4, 1, 2]
第4種劃分左部分為[3, 2, 3, 4],右部分為[1, 2]
第5種劃分左部分為[3, 2, 3, 4, 1],右部分為[2]
每一種劃分下,左部分都有最大值記為 max_left,右部分都有最大值記為 max_right。
求 |max_left - max_right| (左部分最大值與右部分最大值之差的絕對值),最大是多少?
要求:時間複雜度為O(N),額外空間複雜度O(1)。
Solution:
利用輔助陣列,分別存下從0開始的所有長度時的最大值,比如長度為1即只有 arr[0] 時的最大值為 arr[0];長度為2時,最大值為 max(arr[0], arr[1]) ;長度為3時,最大值為 arr[0]、arr[1] 和 arr[2] 中的最大值。將從長度為1一直到長度為 n 時的最大值依次存入輔助陣列。
巧解:用整個陣列的最大值減去 min(arr[0], arr[n-1]) 即為最大值
題目3:摺紙列印
Description:
請把一段紙條豎著放在桌子上,然後從紙條的下邊向上方對摺1次,壓出摺痕後展開。此時摺痕是凹下去的,即摺痕突起的方向指向紙條的背面。如果從紙條的下邊向上方連續對摺2次,壓出摺痕後展開,此時有三條摺痕,從上到下依次是下摺痕、下摺痕和上摺痕。給定一個輸入引數 N,代表紙條都從下邊向上方連續對摺 N 次,請從上到下列印所有摺痕的方向。
例如:N=1時,列印:
down
N=2時,列印:
down
down
up
Solution:
摺痕其實是二叉樹結構。該二叉樹的特點是:根節點是下,每一個子節點的左節點是下,右節點是上。該二叉樹的中序遍歷即為答案,但不需要構造一棵二叉樹,用遞迴方法打印出來即可。
Code:
public class Code_04_PaperFolding {
public static void printAllFolds(int N) {
printProcess(1, N, true);
}
public static void printProcess(int i, int N, boolean down) {
if (i > N) return;
printProcess(i + 1, N, true);
System.out.println(down ? "down " : "up ");
printProcess(i + 1, N, false);
}
public static void main(String[] args) {
int N = 4;
printAllFolds(N);
}
}