二分法题目总结

题目

  1. 剑指 offer 数字在排序数组中出现的次数
  2. 剑指 offer 旋转数组的最小数字
  3. Leetcode Search for a Range
  4. Leetcode Search Insert Position
  5. Leetcode Search a 2D matrix
  6. Leetcode sqrt(x)
  7. 九度 1534 数组中第 K 小的数字
  8. 剑指 offer 二维数组中的查找

 

思路

1. 二分法总体不难, 但是在边界问题的处理上需要格外的小心

2. 上面的题目都是二分查找问题的变形, 要么是二分查找配合 int 特性(1/2 = 0), 要么是利用二分查找的原理来查找

3. 第一题和第三题是等价的, 都是查找一个数在排序数组中的最左出现位置和最右出现位置.

class Solution {
public:
    vector<int> searchRange(int A[], int n, int target) {
        int left = left_pos(A, 0, n-1, target);
        int right = right_pos(A, 0, n-1, target);
        
        if(left < 0 || left >= n || A[left] != target) {
        	left = right = -1;
        }

        vector<int> res;
        res.push_back(left);
        res.push_back(right);

        return res;
    }
    
    int left_pos(int A[], int m, int n, int target) {
    	if(m > n)
    		return m;

    	int mid = (m+n)>>1;

    	// when a[mid] == target, prefer left one
    	if(A[mid] >= target) {
    		return left_pos(A, m, mid-1, target);
    	}else{
    		return left_pos(A, mid+1, n, target);
    	}
    }

    int right_pos(int A[], int m, int n, int target) {
    	if(m > n)
    		return n;

    	int mid = (m+n)>>1;
    	//cout  << mid << endl;
    	// when a[mid] == target, prefer right one
    	if(A[mid] > target) {
    		return right_pos(A, m, mid-1, target);
    	}else{
    		return right_pos(A, mid+1, n, target);
    	}
    }
};

在取最左位置时, 返回 low, 最右位置返回 high.

返回 low 或 high 是由 a[mid] == target 时递归的走向决定的.

取最左位置时, 当 low > high 时退出递归, 假设上一步是 a[mid] == target, 那么上一步的递归走向是 left_pos(A, low, mid-1, target)

mid-1 越界, 所以应当返回 low

 

4. 旋转数组中的最小数字. 这道题考察的是二分法原理.

考虑旋转数组二分查找的原理和以之构建的框架... OK

二分查找递归的方向由 a[mid] 和 target 的关系决定 :

b_search(mid+1, high, target) if(a[mid] >= target)

b_search(low, mid-1, target) if(a[mid] < target)

 

在旋转数组中, 当出现重复元素时, 假如 a[mid] == target, 递归函数的走向不明, 因此不能再使用二分查找了

 

5. 第四题算是 LIS 的子过程.

当 a[mid] == target , 直接返回 mid

递归函数结束时, return low: 函数结束意味着 low > high, 应该返回较大的 low.

二分法最简单的记法: 

若 a[mid] == target 时返回 mid, 那么最终结果返回 low

否则, 最终结果按照思路 3 的分析进行

 

6. 第五题和第八题是二分法的变形. 第五题要注意, 每次进行二分至少要消去一行. 而第八题是从右上角, 每次消去一行

 

7. 第六七题利用到了 int 的性质, int 除以 2 不会有小数产生, 保证结果肯定会收敛. 其中第七题每次假设第 k 小数为 x, 这种设置方法与最大值最小化问题非常类似

 

 

posted @ 2014-03-22 21:47  周卓  阅读(791)  评论(0编辑  收藏  举报