请实现有重复数字的升序数组的二分查找
给定一个 元素有序的(升序)长度为n的整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的第一个出现的target,如果目标值存在返回下标,否则返回 -1
数据范围:
进阶:时间复杂度,空间复杂度
[1,2,4,4,5],4
2
从左到右,查找到第1个为4的,下标为2,返回2
[1,2,4,4,5],3
-1
[1,1,1,1,1],1
0
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 如果目标值存在返回下标,否则返回 -1 * @param nums int整型一维数组 * @param target int整型 * @return int整型 */ public int search (int[] nums, int target) { return search(nums, 0, nums.length-1, target); } public int search (int[] nums, int left, int right, int target) { int middle = (left+right)/2; while(left <= middle && middle <= right) { if (nums[middle] == target) { // 找到了,再往前找(递归) int prev = search(nums, left, middle-1, target); return prev==-1? middle : prev; } // 小于,从左边找 else if (target < nums[middle]) { right = middle-1; } else { left = middle+1; } middle=(left+right)/2; } return -1; } }
import java.util.*; public class Solution { public int search (int[] nums, int target) { //二分查找的一个变形,本题要求有重复数字,所以处理重复数组是一个关键 int low=0; int high=nums.length-1; int mid=0; while(low<=high){ mid=(low+high)/2; if(nums[mid]==target){ while(mid!=0&&(nums[mid-1]==nums[mid])){ //判断所确定元素之前是否有相同元素 mid--; } return mid; }else if(nums[mid]>target){ high=mid-1; }else{ low=mid+1; } } return -1; } }
看一个测试用例[1,2,2,3,4],2
无论是否第一个target,其下标索引都一定会在区间[left, mid]中(即nums[mid]>=target),如此将会right=mid。
public class Solution { public int search (int[] nums, int target) { // write code here int left = 0; int right = nums.length - 1; while (left < right) { // 不要使用(left+right)/2,虽然结果相同,但是若left和right太大,直接相加会导致整形溢出 int mid = left + (right - left) / 2; if (nums[mid] < target) left = mid + 1; else if (nums[mid] >= target) //[left,hight]中去寻找第一个target right = mid; } //right>=0是为了应对这种测试用例[],0 return right>=0 && nums[right]==target ? right : -1; } }
或者,算了,芝姐套用二分查找
的框架:
public class Solution { public int search (int[] nums, int target) { int left = 0; int right = nums.length - 1; //注意这里是<= while (left <= right) { // 不要使用(left+right)/2,虽然结果相同,但是若left和right太大,直接相加会导致整形溢出 int mid = left + (right - left) / 2; if (nums[mid] == target) { //判断mid之前是否有相同元素(即是否是第一个target) //mid!=0,注意是!=,这是输出结果的边界条件 while (mid!=0 && (nums[mid-1]==nums[mid])) --mid; return mid; } else if (nums[mid] < target) left = mid + 1; else if (nums[mid] > target) //[left,hight]中去寻找第一个target right = mid - 1; } return -1; } }
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 如果目标值存在返回下标,否则返回 -1 * @param nums int整型一维数组 * @param target int整型 * @return int整型 */ public int search (int[] nums, int target) { if(nums.length == 0) return -1; // write code here int l = 0; int r = nums.length - 1; while(l < r){ int mid = l + r >> 1; if(nums[mid] >= target) r = mid; else l = mid + 1; } return nums[l] == target ? l : -1; } }
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 如果目标值存在返回下标,否则返回 -1 * @param nums int整型一维数组 * @param target int整型 * @return int整型 */ public int search (int[] nums, int target) { // write code here if(nums == null || nums.length == 0) { return -1; } int left = 0, right = nums.length - 1; while(left <= right) { //注意mid的求法 int mid = left + (right - left) >> 1; //注意中间元素与目标元素比较 if(nums[mid] >= target) { right = mid - 1; } else { left = mid + 1; } if(nums[left] == target) { return left; } //不要忘记累加操作 left++; right++; } return -1; } }
class Solution { public: int search(vector<int>& nums, int target) { if(nums.empty()) return -1; int left = 0, right = nums.size()-1; while(left<right){ int mid = (left+right)/2; if(nums[mid]>target) right = mid-1; else if(nums[mid]<target) left = mid+1; else right = mid; } return nums[left]==target? left:-1; } };
思路:利用while循环,设置左右指针left,right。跳出循环的条件为left>right。mid = (left + right) / 2; 当中间值大于target,将left指针设置为mid + 1。当中间值小于target,将right指针设置为mid - 1;
当找到和target值相同的值时,需要遍历前面是否有相同的值,最小的为所要求的结果。单循环条件一定要注意加上mid <= 1。
public int search (int[] nums, int target) { int left = 0; int right = nums.length - 1; while (left <= right) { int mid = (right + left) / 2; if (nums[mid] == target) { while (mid >= 1 && nums[mid] == nums[mid - 1]) { mid--; } return mid; } else if (nums[mid] > target) { right = mid - 1; } else { left = mid + 1; } } return -1; }
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 如果目标值存在返回下标,否则返回 -1 * @param nums int整型vector * @param target int整型 * @return int整型 */ int search(vector<int>& nums, int target) { // write code here int start = 0, end = nums.size() - 1, middle; while (start <= end) { middle = start + ((end - start) >> 1); if (nums[middle] == target && (middle == 0 || nums[middle - 1] < nums[middle])) return middle; else if (nums[middle] >= target) end = middle - 1; else start = middle + 1; } return -1; } };
int cond(int* nums, int mid, int target) { return *(nums + mid) >= target; } int binary_search(int* nums, int numsSize, int target, int (*cond) (int*, int, int)) { int l = 0, r = numsSize, m; while (l < r) { m = l + ((r - l) >> 1); if (cond(nums, m, target)) r = m; else l = m + 1; } return l; } int search(int* nums, int numsLen, int target) { int index = binary_search(nums, numsLen, target, cond); if (index == numsLen || *(nums + index) > target) return -1; return index; }
public int Search(int[] nums,int target){ //前一个为0 int front = 0; //后一个为数组长度-1 int last = nums.length-1; //返回结果先设为0 int index = 0; //首先满足的条件为左指针小于等于右指针 while(front<=last){ //先计算出中间指针的值 int mid = front + (last - front)/2; //如果中间指针的值和目标值相等 if(nums[mid]==target){ //看看左边是否还有相等值,直到不相等为止 while(mid!=0 && nums[mid-1]==nums[mid]){ index--; } return index; } else if(nums[mid]<target){ //如果中间节点小于目标值,那么就在右半边,右指针不动,左指针在中间节点右侧 left = mid+1; } else{ //同理在左半边,那么右指针变为中间点左一个 right = mid-1; } return -1; } }
int search(vector<int>& nums, int target) { int low = 0, high = nums.size() - 1; while (low <= high) { int mid = low + (high - low) / 2; if (nums[mid] >= target) { high = mid - 1; } else { low = mid + 1; } } if (low < nums.size() && nums[low] == target) { return low; } return -1; }