第一次题解
思路
:将数组分为两份,左边的数组可能是有序的可能是无须的,通过一个while找出[left, mid] 是有序的,这样能找到旋转位置,再根据二分搜索法找出taget值。
自我点评:
- 时间复杂度为log(n)级别
- 应多用注释标记出边界点范围节省调试的时间。
- 局限于找出旋转位置
- 代码较多,理解起来困难
- 以后使用low,hight单词代替 left,right。
class Solution {
fun search(nums: IntArray, target: Int): Int {
if (nums.isEmpty()) return -1
return searchTag(nums, 0, nums.lastIndex, target)
}
private fun searchTag(nums: IntArray, left: Int, right: Int, target: Int): Int {
var mRight = right
var mid = (left + mRight) / 2 // 可优化 (right - left) / 2 + left
// [left, mRight] 有序,查找Tga值
if (nums[left] <= nums[mRight]) return binarySearch(nums, left, mRight, target)
// 找出 [left, mid] 是有序的
while (nums[mid] < nums[left]) {
mRight = mid
mid = (left + mRight) / 2 // 可优化 (right - left) / 2 + left
}
// target 存在 [let, mid] 之间
if (target >= nums[left] && target <= nums[mid]) return binarySearch(nums, left, mid, target)
// [mid+1, right] 从新搜索
return searchTag(nums, mid + 1, right, target)
}
private fun binarySearch(nums: IntArray, left: Int, right: Int, target: Int): Int {
if (left > right) return -1
val mid = (right - left) / 2 + left // 可优化 (right - left) / 2 + left
return when {
nums[mid] == target -> mid
nums[mid] < target -> binarySearch(nums, mid + 1, right, target)
else -> binarySearch(nums, left, mid - 1, target)
}
}
}
优雅解法
思路
:如果中间的数小于最右边的数,则右半段是有序的,若中间数大于最右边数,则左半段是有序的,我们只要在有序的半段里用首尾两个数组来判断目标值是否在这一区域内,这样就可以确定保留哪半边了
class Solution {
fun search(nums: IntArray, target: Int): Int {
if (nums.isEmpty()) return -1
return searchTag(nums, 0, nums.lastIndex, target)
}
private fun searchTag(nums: IntArray, left: Int, right: Int, target: Int): Int {
var low = left
var hight = right
while (low <= hight) {
val mid = (low + hight) / 2
if (target == nums[mid]) return mid
if (nums[mid] < nums[hight]) {// [mid, right]
if (nums[mid]< target && target <= nums[hight]) low = mid + 1 // num[mid] < target <= num[right]
else hight = mid - 1
}else {
if (nums[low] <= target && target < nums[mid]) hight = mid - 1 // num[right] <= target < num[mid]
else low = mid + 1
}
}
return -1
}
}