二分查找
在每一步中根据数组的特点来确定目标元素可能存在的区间,并不断更新左右指针,缩小查找范围,直到找到目标元素或确定目标元素不存在。
1.数组原本是升序的
2.旋转后变成两个升序的数组
3.找到旋转后数组的target元素的下标
具体步骤如下:
- 初始化左右指针,左指针指向数组第一个元素,右指针指向数组最后一个元素。
- 进入循环,判断左指针是否小于等于右指针:
- 计算中间位置的索引。
- 如果中间位置的元素等于目标元素,返回中间位置的索引。
- 如果左边是连续递增的,判断目标元素是否在左边递增的范围内:
- 如果是,更新右指针为mid-1,缩小查找范围为左边部分。
- 如果不是,更新左指针为mid+1,缩小查找范围为右边部分。
- 如果右边是连续递增的,判断目标元素是否在右边递增的范围内:
- 如果是,更新左指针为mid+1,缩小查找范围为右边部分。
- 如果不是,更新右指针为mid-1,缩小查找范围为左边部分。
- 循环结束后仍未找到目标元素,返回-1。
时间复杂度:该算法的时间复杂度为O(log n),其中n是数组的长度。每次循环将查找范围缩小一半,因此时间复杂度为对数级别。
空间复杂度:该算法的空间复杂度为O(1),只需要常数级别的额外空间。
func main (){
nums:=[]int{4,5,6,7,0,1,2}
ans:=search(nums,3)
fmt.Println(ans)
}
func search(nums []int, target int) int { //定义一个函数,接受一个整数数组和一个整数作为参数,返回一个整数
left, right := 0, len(nums)-1 //初始化左右指针,左指针指向数组第一个元素,右指针指向数组最后一个元素
for left <= right { //循环条件:左指针小于等于右指针
mid := (right-left)/2 + left //计算中间位置的索引
if nums[mid] == target { //如果中间位置的元素等于目标元素
return mid //返回中间位置的索引
} else if nums[left] <= nums[mid] { //如果左边是连续递增的
if nums[left] <= target && nums[mid] > target { //如果目标元素在左边递增的范围内
right = mid - 1 //更新右指针
} else { //否则
left = mid + 1 //更新左指针
}
} else { //如果右边是连续递增的
if nums[mid] < target && nums[right] >= target { //如果目标元素在右边递增的范围内
left = mid + 1 //更新左指针
} else { //否则
right = mid - 1 //更新右指针
}
}
}
return -1 //循环结束后仍未找到目标元素,返回-1
}
//时间复杂度:O(logn)
//空间复杂度:O(1)