持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情
太久碰算法题了,今天突然想起来摸一下,发现一个最简单的查找位置,居然花了很长时间,所以打算写一个文章记录一下,我脑子里的坑。
题目
已知存在一个有序且元素不重复的整型数组和一个目标值,查找目标值在该数组中的位置。如果数组中不存在目标值,则返回目标值在数组中应插入的位置。
示例 1:
有序数组: [1,3,5,7,9] ,目标值:7
输出:3
示例 2:
有序数组: [1,3,5,7,9] ,目标值:2
输出:1
示例 3:
有序数组: [1,3,5,7,9] ,目标值:12
输出:5
示例 4:
有序数组: [1] ,目标值:2
输出:1
示例 5:
有序数组: [1] ,目标值:1
输出:0
技术点要求
- Java 语言
- 时间复杂度为 O(log n)
看上去非常简单,是不是,好的,马上开始行动;
我的第一次解法:定义一个index,接收返回值,然后开始判断。因为是有序数组,所以如果他比第一个小,或者比最后一个数大,表示他不在数组里面,位置就是第一个,或者最后一个+1;
然后开始循环数组,如果找到了,index=当前下标,如果没有找到,如果有sortArr[i]<target && sortArr[i+1]>target
也可以,然后index=i+1;
这个思路看上去,没毛病,但是我提交就
好的,通过思考我发现,在i+1可能出现下标越界。然后我开始修改,那就把循环改一下。一个是0-length,一个是0-length-1;i+1那个放在0-length-1,保证了不越界,0-length就使用找得到的。听上去,也没有问题,然后修改,提交,终于》》》》》失败;
然后我发现,如果数组只有一个数,那么i和i+1就有问题啊!!!!
然后就改成了下面这个鬼样子
public class BinarySearchSolution{
/**
* 搜索插入位置
* @param sortArr 有序不重复数组
* @param target 目标值
* @return 目标值在数组中的正确位置
*/
public static int findIndex(int[] sortArr, int target) {
//代码编辑区 start
int index=-1;
if(sortArr[0]>target){
index=0;
}
if(sortArr[sortArr.length-1]<target)
if(sortArr[sortArr.length-1]<target){
index=sortArr.length;
}
for(int i=0;i<sortArr.length;i++){
if(sortArr[i]==target){
index=i;
break;
}
if(sortArr.length>1){
if(sortArr[i]<target && sortArr[i+1]>target){
index=i+1;
break;
}
}else{
if(sortArr[0]>target){
index=0;
}
if(sortArr[sortArr.length-1]<target){
index=sortArr.length;
}
}
}
return index;
//代码编辑区 end
}
public static void main(String[] args) {
int [] sortArr ={1};
int target = 1 ;
System.out.println(findIndex(sortArr, target));
}
}
好家伙,还是不能通过,而且修改后代码非常冗余,也不利于读代码,感觉自己好废物。
于是重新思考: 想到了二分查找:
思路:定义left=0,right=sortArr.length-1,定义mind=(left+right)/2
如果sortArr[mind]=target 输出mind
如果比target小,right=mind-1;
如果比target大,right=mind+1;
int left = 0, right = sortArr.length - 1;
while(left <= right) {
int mid = (left + right) / 2;
if(sortArr[mid] == target) {
return mid;
} else if(sortArr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
System.out.println(left);
return left;
}
终于,它通过了,但是我又怎么会放弃最开始那个解法,于是开始反复修改,分析
分析: 分两种情况,找到和没找到,找到就是返回下标,没有找到就是插入。 如果比第一个小,返回下标0 如果比最后一个大,返回length+1 然后我就开始写代码,先是比第一个小比最后一个大 然后开始循环数组,如果找到一个值等于target,就返回下标 没有就是 如果第i个比target小,第i+1比target大,返回i+1
public class BinarySearchSolution{
/**
* 搜索插入位置
* @param sortArr 有序不重复数组
* @param target 目标值
* @return 目标值在数组中的正确位置
*/
public static int findIndex(int[] sortArr, int target) {
//代码编辑区 start
int index=-1;
if(sortArr[0]>target){
index=0;
}else if(sortArr[sortArr.length-1]<target){
index=sortArr.length;
}else{
for(int i=0;i<sortArr.length;i++){
if(target==sortArr[i]){
index=i;
}else if(sortArr[i]<target && sortArr[i+1]>target){
index=i+1;
}
}
}
return index;
//代码编辑区 end
}
public static void main(String[] args) {
int [] sortArr ={1};
int target = 1 ;
System.out.println(findIndex(sortArr, target));
}
}
终于,它也通过了,这里我就添加了一点if else。
然后我就开始百度寻求其他解法
暴力解法
public static int findIndex(int[] sortArr, int target) {
//代码编辑区 start
for(int i=0;i<sortArr.length;i++){
if(sortArr[i]>=target){
return i;
}
}
return sortArr.length;
}\
为啥人家的暴力解法这么简单!!!o no
很清晰的:因为从0开始,所以如果目标值小于第一个数,自然小于全部,然后不管查找还是插入,位置都是i。如果没在小于等于里面,看到大于数组最后一个数;
果然,今天发现算法的优点了,虽然这个属于暴力解法,但是思路和我第一次想的差不多,但是代码非常简练。