美文网首页
二分查找

二分查找

作者: wayyyy | 来源:发表于2017-10-18 00:37 被阅读0次
    二分查找.png
    非递归版本
    int binarySearch(const vector<int>& vec, int targetNum)
    {
        int lo = 0;
        int hi = vec.size()-1;
    
        while(lo <= hi) {
            int mid = (hi + lo) / 2;    // mid=lo+(hi-lo)/2 这样写还可以防止溢出
            
            if (vec[mid] == targetNum)
                return mid;
            else if (vec[mid] < targetNum)
                lo = mid + 1;
            else if (vec[mid] > targetNum)
                hi = mid - 1;
        }
    
        return -1;
        // return lo  lo是该数据应该插入的位置。
    }
    
    递归版本
    int binarySearch(const vector<int>& vec, int lo, int hi, int targetNum)
    {   
        if (lo <= hi)
            return -1;
        
        int mid = (hi + lo)/2;  
    
        if (vec[mid] < targetNum)
            return binarySearch(vec, mid+1, hi, targetNum);
        else if (vec[mid] > targetNum)
            return binarySearch(vec, lo, mid-1, targetNum);
        else
            return mid;
    } 
    
    对二分查找分析
    • 在N个有序数组中,进行二分查找最多需要(log2N + 1)次比较(无论是否成功)

      总共有n个元素,渐渐分下去就是n,n/2,n/4,.... n/(2^k)(接下来操作元素的个数),其中k就是循环 的次数,直到n/2^k=1/2,可得k = log2n + 1,(是以2为底,n的对数)所以时间复杂度可以表示O(h)=O(log2n)

    35. 搜索插入位置
    class Solution {
    public:
        int searchInsert(vector<int>& nums, int target) {
            int startIndex = 0;
            int endIndex = nums.size() - 1;
            int midIndex = 0;
            while(startIndex <= endIndex)
            {
                auto midIndex = startIndex + (endIndex - startIndex) / 2;
                if (nums[midIndex] == target)
                    return midIndex;
                else if (nums[midIndex] > target)
                    endIndex = midIndex - 1;
                else if (nums[midIndex] < target)
                    startIndex = midIndex + 1;
            }
    
            return startIndex;
        }
    };
    
    367. 有效的完全平方数
    • 暴力
    • 二分查找
      class Solution {
      public:
          bool isPerfectSquare(int num) {
              int lo = 1;
              int hi = num;
            
              while(lo <= hi)
              {
                  int mid = lo + (hi - lo)/2;  // 可以用>>
                  if (mid * mid == num)  // 这里注意溢出
                      return true;
                  else if (mid * mid > num)
                      hi = mid - 1;
                  else 
                      lo = mid + 1;
              }
            
              return false;
          }
      };
      
    • 数学定理
      1 + 3 + 5 + ... + (2n - 1) = n ^ 2
      class Solution {
      public:
          bool isPerfectSquare(int num) {
              int i = 1;
              while(num > 0) {
                   num -= i;
                   i += 2;
              }
            
              return num == 0;
          }
      };
      
    • 牛顿迭代法
      牛顿迭代法参见 https://www.cnblogs.com/qlky/p/7735145.html
      class Solution {
      public:
          bool isPerfectSquare(int num) {
                if (num == 1) {
                    return true;
                }
                int i = num / 2;
                while((double)i * i > num) {
                    i = (i + num / i) / 2;
                }
                return i * i == num;
          }
      };
      
    278. 第一个错误的版本
    场景一:isBadVersion(mid) => false
    
     1 2 3 4 5 6 7 8 9
     G G G G G G B B B       G = 正确版本,B = 错误版本
     |       |       |
    left    mid    right
    
    场景二:isBadVersion(mid) => true
    
     1 2 3 4 5 6 7 8 9
     G G G B B B B B B       G = 正确版本,B = 错误版本
     |       |       |
    left    mid    right
    
    
    bool isBadVersion(int version);
    
    class Solution {
    public:
        int firstBadVersion(int n) {
            int left = 1;
            int right = n;
            while (left < right) 
            {
                int mid = left + (right - left) / 2;
                if (isBadVersion(mid)) 
                    right = mid;
                else 
                    left = mid + 1;
            }
            
            return left;
        }
    };
    
    数组中出现次数超过一半的数字
    在排序数组中查找元素的第一个和最后一个位置
    • 线性扫描
      从左到右,从右到左
    • 二分
      class Solution {
      public:
          vector<int> searchRange(vector<int>& nums, int target) 
          {
              int start = findStartIndex(nums, 0, nums.size()-1, target);
              int end = findEndIndex(nums, 0, nums.size()-1, target); 
              return vector<int>{start, end};
          }
        
          int findStartIndex(const vector<int>& nums, int lo, int hi, int target)
          {
              while(lo <= hi)
              {
                  int mid = lo + (hi-lo)/2;
                  if (nums[mid] == target)
                  {
                      if (mid != 0)
                      {
                          if (nums[mid-1] != target)
                              return mid;
                          else
                              hi = mid - 1;
                      }
                      else
                      {
                          return 0;
                      }
                  }
                  else if (nums[mid] > target)
                  {
                      hi = mid - 1;
                  }
                  else if (nums[mid] < target)
                  {
                      lo = mid + 1;
                  }
              }
              
              return -1;
          }
        
          int findEndIndex(const vector<int>& nums, int lo, int hi, int target)
          {
              while(lo <= hi)
              {
                  int mid = lo + (hi-lo)/2;
                  if (nums[mid] == target)
                  {
                      if (mid != nums.size()-1)
                      {
                          if (nums[mid+1] != target)
                              return mid;
                          else
                              lo = mid + 1;
                      }
                      else
                      {
                          return nums.size()-1;
                      }
                  }
                  else if (nums[mid] > target)
                  {
                      hi = mid - 1;
                  }
                  else if (nums[mid] < target)
                  {
                      lo = mid + 1;
                  }
              }
              
              return -1;
          }
      };
      
    50. Pow(x, n)
    153. 寻找旋转排序数组中的最小值
    • 暴力搜索整个数组,找出最小值
    • 二分法

    相关文章

      网友评论

          本文标题:二分查找

          本文链接:https://www.haomeiwen.com/subject/qkojuxtx.html