题目

描述

  • 请实现有重复数字的升序数组的二分查找
    给定一个 元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的第一个出现的target,如果目标值存在返回下标,否则返回 -1。

方法一

思路

在有重复数字的升序数组中找一个下标最小的target,且题目要求就是使用二分查找,所以方法必然是二分查找了,只需要处理重复数字就可以了,那么很容想到,在找到target后,再往左遍历,找到target最小的下标。

具体步骤

  • 1.求mid;
  • 2.比较nums[mid]与target值;
  • 3.不同,返回1;
  • 4.相同,从当前点,往左遍历,直至与target值不同时,返回加一的下标。
  • 代码如下:
    import java.util.*;
    public class Solution {
      /**
       * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
       *
       * 如果目标值存在返回下标,否则返回 -1
       * @param nums int整型一维数组 
       * @param target int整型 
       * @return int整型
       */
      public int search (int[] nums, int target) {
          // 数组为空直接返回
          if (nums == null || nums.length == 0){
              return -1;
          }
          int right = nums.length - 1;
          int left = 0;
          int mid = 0;
          // 二分查找
          while (left <= right){
              mid = left + (right - left)/2;
              if (nums[mid] < target){
                  left = mid + 1;
              }else if(nums[mid] > target)
              {
                  right = mid - 1;
              }else{
                  // 找到target,往左找第一次出现的下标
                  while(mid != 0 && nums[mid] == nums[mid-1]){
                      --mid;
                  }
                  return mid;
              }
          }
          return -1;
      }
    }
  • 时间复杂度:,二分查找。
  • 空间复杂度:,常数级空间复杂度。

    方法二

    思路

  • 方法一在找到target值后还需要往左遍历,其实是可以省去的,可以直接通过二分查找往左逼近。如:当nums[mid]<target时,左指针left直接置为mid+1,慢慢逼近target。

    具体步骤

  • 参考下图的栗子:
    图片说明
  • 代码如下:
    import java.util.*;
    public class Solution {
    /**
    * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
    *
    * 如果目标值存在返回下标,否则返回 -1
    * @param nums int整型一维数组 
    * @param target int整型 
    * @return int整型
    */
    public int search (int[] nums, int target) {
       // 数组为空直接返回
       if (nums == null || nums.length == 0){
           return -1;
       }
       int right = nums.length - 1;
       int left = 0;
       int mid = 0;
       // 往左逼近
       while (left < right){
           mid = left + (right - left) / 2;
           // target在mid右边
           if (nums[mid] < target){
               left = mid + 1;
           }else{
               right = mid;
           }
       }
       // 返回第一次出现的下标
       return nums[left] == target ? left : -1;
    }
    }
  • 时间复杂度:,二分查找。
  • 空间复杂度:,常数级空间复杂度。