二分查找(Binary Search)入门:一道简单题+四道变形题

  1. 二叉查找的前提条件:有序 数组
  2. 为了对于在有序链表中也可用“二分查找” — 有了跳表这个数据结构
  3. 解题方法:递归、循环
  4. 写二分查找的题目精髓就是:搜索区间 记心里!!

一、一道简单题

  1. 有序数组
  2. 无重复元素
  3. 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。【寻找一个数】
   public int search(int[] nums, int target) {
        //搜索区间为左闭右闭:[left, right]
        int left = 0, right = nums.length - 1;

        //当搜索区间为空时,跳出循环
        while(left <= right) {
            int mid = left + (right - left) / 2;

            if(nums[mid] == target) {
                return mid;
            }
            else if(nums[mid] < target) {
                left = mid + 1;
            }
            else if(nums[mid] > target) {
                right = mid - 1;
            }
        }
        
        return -1;
    }

二、四道变形题

  1. 有序数组中有重复元素
  2. 图片摘自[极客时间-徐争老师的数据结构与算法之美的课]

在这里插入图片描述

2.1 在有重复元素的有序数组中查找第一个值等于给定值的元素(在排序数组中查找元素的第一个位置)

法一:

找最左位置:由右逼近

   public int search(int[] nums, int target) {
        int left = 0, right =  nums.length - 1;

        while(left <= right) {
            int mid = left + (right - left) / 2;
            if(nums[mid] > target) {
                right = mid - 1;
            }
            else if(nums[mid] < target) {
                left = mid + 1;
            }
            //进一步缩小搜索区间
            else if(nums[mid] == target) {
                right = mid - 1;
            }
        }
        // 最后要检查 left 越界的情况
        if(left <= nums.length - 1 && nums[left] == target) {
            return left;
        }
        else {
            return -1;
        }
    }

法二:

public int bsearch(int[] a, int n, int value) {
  int low = 0;
  int high = n - 1;
  while (low <= high) {
    int mid =  low + ((high - low) >> 1);
    if (a[mid] > value) {
      high = mid - 1;
    } else if (a[mid] < value) {
      low = mid + 1;
    } else {
      if ((mid == 0) || (a[mid - 1] != value)) return mid;
      else high = mid - 1;
    }
  }
  return -1;
}

2.2 在有重复元素的有序数组中查找最后一个值等于给定值的元素(在排序数组中查找元素的最后一个位置)

法一:

找最右位置:由左逼近

   public int searchRight(int[] nums, int target) {
        int left = 0, right =  nums.length - 1;
        
        while(left <= right) {
            int mid = left + (right - left) / 2;
            if(nums[mid] > target) {
                right = mid - 1;
            }
            else if(nums[mid] < target) {
                left = mid + 1;
            }
            //向右缩小区间
            else if(nums[mid] == target) {
                left = mid + 1;
            }
        }
        if(right >= 0 && nums[right] == target) {
            return right;
        }
        else {
            return -1;
        }
    }

法二:

public int bsearch(int[] a, int n, int value) {
  int low = 0;
  int high = n - 1;
  while (low <= high) {
    int mid =  low + ((high - low) >> 1);
    if (a[mid] > value) {
      high = mid - 1;
    } else if (a[mid] < value) {
      low = mid + 1;
    } else {
      if ((mid == n - 1) || (a[mid + 1] != value)) return mid;
      else low = mid + 1;
    }
  }
  return -1;
}

2.3 在有重复元素的有序数组中查找第一个大于等于给定值的元素

在有序数组中,查找第一个大于等于给定值的元素。
比如,数组中存储的这样一个序列:3,4,6,7,10。
查找第一个大于等于 5 的元素,那就是 6。

public int bsearch(int[] a, int n, int value) {
  int low = 0;
  int high = n - 1;
  while (low <= high) {
    int mid =  low + ((high - low) >> 1);
    if (a[mid] >= value) {
      if ((mid == 0) || (a[mid - 1] < value)) return mid;
      else high = mid - 1;
    } else {
      low = mid + 1;
    }
  }
  return -1;
}

2.4 在有重复元素的有序数组中查找最后一个小于等于给定值的元素

public int bsearch7(int[] a, int n, int value) {
  int low = 0;
  int high = n - 1;
  while (low <= high) {
    int mid =  low + ((high - low) >> 1);
    if (a[mid] > value) {
      high = mid - 1;
    } else {
      if ((mid == n - 1) || (a[mid + 1] > value)) return mid;
      else low = mid + 1;
    }
  }
  return -1;
}
发布了581 篇原创文章 · 获赞 97 · 访问量 29万+

猜你喜欢

转载自blog.csdn.net/gx17864373822/article/details/104845760