题目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);
}
}