给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 1:
输入: [1,3,5,6], 5
输出: 2
示例 2:
输入: [1,3,5,6], 2
输出: 1
示例 3:
输入: [1,3,5,6], 7
输出: 4
示例 4:
输入: [1,3,5,6], 0
输出: 0
做这个题之前,我是没有二分法的思路的,想到的就是暴力for循环遍历,时间复杂度为O(n),代码如下:
class Solution {
public int searchInsert(int[] nums, int target) {
if (nums == null || nums.length == 0 || target == 0) {
return 0;
}
for (int i = 0; i < nums.length; i++) {
if (nums[i] == target) {
return i;
}
if (target < nums[i]) {
return i - 1 > 0 ? i : 0;
}
if (i + 1 == nums.length) {
return nums.length;
}
if (target > nums[i] && target <= nums[i + 1]) {
return i + 1;
}
}
return 0;
}
}
然后内存占用很大:
看了题解以后发现可以用二分法,然后我又去复习了一遍二分法。
二分法的描述是这样的:
给定一列值,给出一个数字,返回这个数字在这列值中的索引值,如果这个数字没有在这列值当中,返回-1
二分法,原理很简单,但是有一个前提,就是必须是有序的,什么意思呢,就是如果给定一列值,如果我们想要使用二分查找法的话,这列值的顺序,就是必须是一个有序的,所以,我们在拿到一列值的时候,就首先必须得对它排序,然后才能使用二分查找法。那么,怎么去查找呢?就是首先找出这列值靠近中间位置的值,如果这列值的长度是奇数的话,那么就是这列值的中位数,如果是偶数的话,可以找中间的两个值的任意一个即可,找到以后,拿我们要去查找的这个值和中间的这个值去比较,我们记要查找的值为a,中间的那个值为b,如果a>b,那么就说明,a有可能在b的左边,但是一定不可能在b的右边,当然,如果a==b的话,那么我们就找到了,可以直接返回。如果a<b的话,那么就说明,a有可能在b的右边,但是一定不可能在b的左边,然后我们此时将我们要查找的这列值缩短一下,怎么缩短呢?如果a>b,那么我们就把[0,b]作为新的一列值,如果a<b,那么我们就把[b,值长度]作为新的一列值,再按照上面的思路一直找下去,直到找到最后一个元素,如果没有找到,返回-1
代码也很简单,力扣上也有对应的题目,顺便可以做了然后AC加一
https://leetcode-cn.com/problems/binary-search/
public int search(int[] nums, int target) {
int result = Arrays.binarySearch(nums,target);
return result < 0 ? -1 : result;
}
你以为是上面这样?不不不,我就是皮一下,这个是Java自带的二分查找,我们需要自己实现一个算法:
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length;
while (left <= right) {
int middle = (left + right) / 2;
if (middle >= nums.length) {
return -1;
}
if (nums[middle] > target) {
right = middle - 1;
} else if (nums[middle] < target) {
left = middle + 1;
} else {
return middle;
}
}
return -1;
}
}
首先,我们定义left和right值分别为0和数组的长度,确保我们能够从左查找到右,然后我们定义一个while循环,用于遍历,跳出循环的条件就是left>right的时候,因为这个时候说明我们已经查找完了,然后我们去计算最中间的那个数,有可能你会问,int middle = (left + right) / 2;
不用考虑小数的情况吗?其实不用特意的去计算,直接向上取整就行,然后下面一部为了防止要查找的数字到最后一个还没找到,加了一个判断,直接返回-1,接着我们去判断,如果中间的那个数大于我们的target,那么我们就把中间的这个数-1,然后给right,否则+1给left,如果相等,直接返回。
那么,最开始的我们那个题目,怎么使用二分法呢?代码如下:
class Solution {
public int searchInsert(int[] nums, int target) {
int n = nums.length;
int left = 0, right = n - 1, ans = n;
while (left <= right) {
int mid = ((right - left) >> 1) + left;
if (target <= nums[mid]) {
ans = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
return ans;
}
}