「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战」。
前言:emmm,题目看了好几分钟,一直在想题目要干啥。。。看了一眼评论,想着难道真的是我想的那样,于是写了一下简单的暴力解法,accept。。。当然,题目为中等,解法肯定不是我这个。
题目:给定一个数组(数组中元素唯一)和一个target, 如果target在数组中,返回其下标,如果不在返回-1。此外还介绍了旋转数组,指的就是数组在某个下标i处进行旋转,旋转后数组就变成arr[i, len, 0, i]。举例:[1, 2, 4]在i=1处旋转,则数组变成[2,4,1]。
暴力解法
暴力解法很简单,就是遍历数组,查看数组每个元素是否等于target,如果等于就返回下标,不等就直到循环结束返回-1,代码如下:
public int search(int[] nums, int target) {
int len=nums.length;
for(int i=0;i<len;i++){
if(nums[i] == target){
return i;
}
}
return -1;
}
最终运行结果耗时0ms,超过100%人。。。。
当然编题目的人肯定是不希望答案是这个,毕竟前面花费那么多文字解释什么是旋转数组,并且进阶版要求时间复杂度为,上述解法的时间复杂度为。
二分法
看到时间复杂度为,首先想到的就是二分法,本题给的数组是原数组保持有序后经过翻转的数组,此时使用二分法将数组二分,则数组必然有一个保持有序,另一侧部分有序。**通过判断target在哪个数组来再次进行二分就是本题的关键点。**其实就是判断数组的哪部分有序。
可以通过判断首元素与mid元素的大小来确定[0-mid]是否有序,如果有序则直接判断target是否在这个范围,即nums[0]<target<nums[mid],是则更新r,否则更新l。如果无序则判断target是否在nums[mid]<target<nums[n-1],如果在则更新l,否则更新r。代码如下:
public int search2(int[] nums, int target) {
int l=0, r=nums.length-1;
while (l<=r){
int mid = (l + r) /2;
if(nums[mid] == target){
return mid;
}
if(nums[0]<=nums[mid]){ //这一步用来判断数组哪部分有序,该条件为左边有序
if(nums[0]<=target&&target<nums[mid]){
r = mid - 1;
}else {
l = mid + 1;
}
}else { // 否则右边有序
if(nums[mid]<target&&target<=nums[nums.length-1]){
l = mid + 1;
}else {
r = mid - 1;
}
}
}
return -1;
}
时间复杂度为, 空间复杂度为。