zoukankan      html  css  js  c++  java
  • 二分法总结

    二分查找本身并不难, 难的是二分查找的扩展问题

    1. 假如 target 不在数组中, 输入其应该在的位置

    2. 找到大于 target 的最小值的位置或小于 target 的最大值的位置

    3. target 在数组中连续出现多次, 分别找到 target 的最左位置和最右位置

    int _bsearch(int A[], int m, int n, int target) {

      if(m > n)                                              ----------------------------- 变量 x

        return m;                                       ----------------------------- 变量 y

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

      if(A[mid] == target) {        

       code here                                        ----------------------------- 变量 z

      }

    }

    在二分查找的框架内, 大致有 3 个可变的位置, 分别是 x, y, z 处

    具体来说

    1. x 可以填写 m >=n 或 m > n

    2. y 可以填写 return m, return n, return min(n,m)...

    3. z 可以填写 b_search(A, mid+1, n, target) or b_search(A, m, mid-1, target)

    一般来讲, 

    x 处都要填 m > n, 因为当 m==n 时, 代码还需要向下走进行验证

    y 处是最难把握的了, 需要具体情况具体分析

    z 的话需要考虑 当 a[mid] == target 时, 我们有怎样的需求, 再做选择

    例题

    1. Leetcode Search in Rotated Sorted Array

    class Solution {
    public:
        int search(int A[], int n, int target) {
        	if(n < 1)
        		return -1;
    
    		int pivot = A[0];        
    		int pivot_pos = find_pos(A, 0, n-1, pivot);
    
    		//cout << "pivot at " << pivot_pos << endl;
    
    		int got;
    		if(pivot == target) {
    			return 0;
    		}else if(pivot < target) {
    			got = b_search(A, 0, pivot_pos-1, target);
    			if(got < 0 || got >= pivot_pos)
    				return -1;
    			return got;
    		}else{
    			got = b_search(A, pivot_pos, n-1, target);
    			if(got < pivot_pos || got >= n)
    				return -1;
    			return got;
    		}
    
    
        }
    
        int find_pos(int A[], int m, int n, int pivot) {
        	if(m > n)
        		return m;
    
        	int mid = (m+n)>>1;
        	//cout << "mid " << mid << endl;
        	if(A[mid] >= pivot) {
        		return find_pos(A, mid+1, n, pivot);
        	}else {
        		return find_pos(A, m, mid-1, pivot);
        	}
        }
    
        int b_search(int A[], int m, int n, int pivot) {
        	if(m > n) {
        		return -1;
        	}
    
        	int mid = (m+n)>>1;
        	if(A[mid] == pivot) {
        		return mid;
        	}else if(A[mid] < pivot) {
        		return b_search(A, mid+1, n, pivot);
        	}else{
        		return b_search(A, m, mid-1, pivot);
        	}
    
        }
    };
    

      

    2. Leetcode  Search Insert Position

    y 处. 当 m > n 时, 说明有两种情况发生了, 第一, 上一步是 b_search(A, mid+1, n, target) 这说明, 待求位置在 mid "右边"(A[mid] < target), 所以返回 m (mid+1);  第二种, 上一步是 b_search(A, m, mid-1, target), 说明 (A[mid] > target) 且这是最后一步递归(以发生越界 m>n), 所以我们要插入的位置在mid-1右边, 仍然填 m

    #include <iostream>
    using namespace std;
    
    class Solution {
    public:
        int searchInsert(int A[], int n, int target) {
            int pos = b_search(A, 0, n-1, target);
            return pos;
        }
    
        int b_search(int A[], int m, int n, int target) {
        	if(m > n)
        		return m;
    
        	int mid = (m+n)>>1;
        	//cout << mid << endl;
        	if(A[mid] == target) {
        		return mid;
        	}else if(A[mid] > target) {
        		return b_search(A, m, mid-1, target);
        	}else{
        		return b_search(A, mid+1, n, target);
        	}
        }
    };
    

      

    3. Leetcode Search for a Range

    x 处. m==n 时, 仍需要判断, 所以向下走

    z 处. 求 left_position 时, 当 A[mid] == target 时, 我们希望看看 mid 左边是否还有更合适的解, 所以应该 b_search(A, m, mid-1, target) 强制向左, 求 right_position 同理

    y 处. 求 left_position 时, 我们总是强制向左, 所以最终会越界, left_position 应该是越界的右端, 返回 m

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

      

  • 相关阅读:
    python学习之函数的参数
    python学习之文件修改及函数基础作业
    日志模块与 re 模块
    day23
    常用模块(二)
    day 22
    python 常用模块
    软件开发目录规范
    day 20
    python 的模块与包
  • 原文地址:https://www.cnblogs.com/xinsheng/p/3470196.html
Copyright © 2011-2022 走看看