请实现有重复数字的升序数组的二分查找
给定一个 元素有序的(升序)长度为n的整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的第一个出现的target,如果目标值存在返回下标,否则返回 -1
数据范围:
进阶:时间复杂度
,空间复杂度%5C)
[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;
}