Analysis of Algorithms
3-SUM in quadratic time. Design an algorithm for the 3-SUM problem that takes time proportional to n 2 n^2 n2 in the worst case. You may assume that you can sort the n integers in time proportional to n 2 n^2 n2 or better.
利用two pointer的思想进行处理,复杂度为 O ( N 2 ) O(N^2) O(N2)
public int threeSum(int[] a) {
int count = 0;
// 需要先进行排序处理
Arrays.sort(a);
// 循环中保证a[i]<a[j]<a[k]
for (int i = 0; i < a.length - 2; i++) {
int j = i + 1;
int k = a.length - 1;
// j和k从两头向中间移动
while (j < k) {
int sum = a[i] + a[j] + a[k];
if (sum == 0) {
count++;
// 处理三元组元素相同的情况
if (a[j] == a[j + 1]) {
j++;
} else {
k--;
}
} else if (sum < 0) {
j++;
} else {
k--;
}
}
}
return count;
}
Search in a bitonic array. An array is bitonic if it is comprised of an increasing sequence of integers followed immediately by a decreasing sequence of integers. Write a program that, given a bitonic array of nn distinct integer values, determines whether a given integer is in the array.
- Standard version: Use ∼3lgn compares in the worst case.
- Signing bonus: Use ∼2lgn compares in the worst case (and prove that no algorithm can guarantee to perform fewer than ∼2lgn compares in the worst case).
~3lgn: 1lgn用于二分查找最大值,划分左右区间;1lgn用于二分查找左区间;1lgn用于二分查找右区间
~2lgn: 节省1lgn关键在于不找最大值,直接依据不同情况来划分左右区间并进行查找。
-
a[mid]>a[mid-1],中间元素在左边递增区间时:
如果key>a[mid],说明key只可能在mid右边,那么问题就变为在一个更小的抛物线上找key,递归进行处理即可;如果key<a[mid],那么key既可能在mid左边,也可能在mid右边,若在左边只要对左半边进行二分查找,若在右边也可以直接对右半部分的抛物线进行二分查找,原因在于key<a[mid],那么key只可能在横向红线的下方出现,即使key在右半部分也只会在右半部分的递减区域出现。 -
a[mid]>a[mid+1],中间元素在右边递减区域时:与上述情况正好相反。
public class Bitonic {
// 处理抛物线部分
public boolean searchBitonic(int[] a, int left, int right, int key) {
int mid = (left + right) / 2;
// 直接找到key返回
if (key == a[mid]) {
return true;
}
if (a[mid] > a[mid - 1]) { // mid在左侧递增部分
if (key > a[mid]) { // 递归处理右部分抛物线
return searchBitonic(a, mid + 1, right, key);
} else { // 对左右两部分进行二分查找
return searchLeft(a, left, mid - 1, key) || searchRight(a, mid + 1, right, key);
}
} else if (a[mid] > a[mid + 1]) { // mid在右侧递减部分
if (key > a[mid]) { // 递归处理左部分抛物线
return searchBitonic(a, left, mid - 1, key);
} else { // 对左右两部分进行二分查找
return searchRight(a, mid + 1, right, key) || searchLeft(a, left, mid - 1, key);
}
}
}
// 递增部分二分查找
private boolean searchLeft(int[] a, int left, int right, int key) {
while (left <= right) {
int mid = (left + right) / 2;
if (a[mid] == key) {
return true;
}
if (a[mid] < key) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return false;
}
// 递减部分二分查找
private boolean searchRight(int[] a, int left, int right, int key) {
while (left <= right) {
int mid = (left + right) / 2;
if (a[mid] == key) {
return true;
}
if (a[mid] < key) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return false;
}
}
Egg drop. Suppose that you have an nn-story building (with floors 1 through nn) and plenty of eggs. An egg breaks if it is dropped from floor TT or higher and does not break otherwise. Your goal is to devise a strategy to determine the value of TT given the following limitations on the number of eggs and tosses:
- Version 0: 1 egg, ≤T tosses.
- Version 1: ∼1lgn eggs and ∼1lgn tosses.
- Version 2: ∼lgT eggs and ∼2lgT tosses.
- Version 3: 2 eggs and ∼ 2 n 2\sqrt{n} 2n tosses.
- Version 4: 2 eggs and ≤ c T c\sqrt{T} cT tosses for some fixed constant c.
以下分析转载自 https://www.cnblogs.com/evasean/p/7208986.html
version 0: 拿着一个鸡蛋从1~n依次扔就可以,到floor T会碎,故复杂度为≤T。
version 1: 采用二分查找,首先从n/2层开始扔: if(鸡蛋碎) 从(n/2)/2层开始扔;else 从n/2+(n/2)/2层开始扔。二分方法需要lgn个鸡蛋尝试lgn次。
version 2: 依次从1, 2, 4, 8, 16, 32,… 2 k 2^k 2k开始扔,如果鸡蛋在 2 k 2^k 2k碎了,那么 2 k − 1 ≤ T ≤ 2 k 2^{k-1}≤T≤2^k 2k−1≤T≤2k,这时已经使用了 lgT 次步,接下来在 [ 2 k − 1 + 1 , 2 k ) [2^{k-1}+1,2^{k}) [2k−1+1,2k)区间进行version 1的二分查找方法,需要花费lgT步。这两种操作加起来总共花费2lgT步。
version 3: 将0~n层楼分成 [ 1 , n − 1 ] [1, \sqrt{n}-1] [1,n−1], [ n , 2 n − 1 ] [\sqrt{n}, 2\sqrt{n}-1] [n,2n−1], [ 2 n , 3 n − 1 ] [2\sqrt{n},3\sqrt{n}-1] [2n,3n−1]… [ k n , ( k + 1 ) n − 1 ] [k\sqrt{n}, (k+1)\sqrt{n}-1] [kn,(k+1)n−1]…个区间,用一个鸡蛋分布从1开始在各个区间的起始楼层扔,如果在 k n k\sqrt{n} kn层碎了,那就从 ( k − 1 ) n + 1 (k-1)\sqrt{n}+1 (k−1)n+1开始逐层扔。第一步区间选择用了 n \sqrt{n} n的复杂度,第二步区间内部扔鸡蛋用了 n \sqrt{n} n的复杂度,总共用了 2 n 2\sqrt{n} 2n。
version 4: 尝试从1, 4, 9, 16, 25,… ( k − 1 ) 2 (k-1)^2 (k−1)2, k 2 k^2 k2…楼层扔鸡蛋,加入鸡蛋在楼层 k 2 k^2 k2碎了,意味着 ( k − 1 ) 2 ≤ T ≤ k 2 (k-1)^2 ≤T≤ k^2 (k−1)2≤T≤k2,这一步尝试了 T \sqrt{T} T次 ( k = T ) (k=\sqrt{T}) (k=T)。接着从楼层 ( k − 1 ) 2 + 1 (k-1)^2+1 (k−1)2+1开始逐层扔,最多尝试至 k 2 − 1 k^2-1 k2−1结束,这一步需要尝试 k 2 − 1 − ( k − 1 ) 2 − 1 + 1 = 2 T − 2 k^2-1-(k-1)^2-1+1=2\sqrt{T}-2 k2−1−(k−1)2−1+1=2T−2次。总共用了 3 T − 2 3\sqrt{T}-2 3T−2次。
参考
Bitonic search - iteye_12150
Coursera Algorithms week1 算法分析 练习测验: Egg drop 扔鸡蛋问题 - evasean