package top100liked import "testing" // https://leetcode.cn/problems/search-in-rotated-sorted-array/?envType=study-plan-v2&envId=top-100-liked // 33. 搜索旋转排序数组 // // 整数数组 `nums` 按升序排列,数组中的值 互不相同 。 // 在传递给函数之前,`nums` 在预先未知的某个下标 `k`(`0 <= k < nums.length`)上进行了 向左旋转,使数组变为 `[nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]`(下标 从 0 开始 计数)。例如, `[0,1,2,4,5,6,7]` 下标 `3` 上向左旋转后可能变为 `[4,5,6,7,0,1,2]` 。 // 给你 旋转后 的数组 `nums` 和一个整数 `target` ,如果 `nums` 中存在这个目标值 `target` ,则返回它的下标,否则返回 `-1` 。 // 你必须设计一个时间复杂度为 `O(log n)` 的算法解决此问题。 // 示例 1: // 输入:nums = [4,5,6,7,0,1,2], target = 0 // 输出:4 // 示例 2: // 输入:nums = [4,5,6,7,0,1,2], target = 3 // 输出:-1 // 示例 3: // 输入:nums = [1], target = 0 // 输出:-1 // // 提示: // - `1 <= nums.length <= 5000` // - `-10^4 <= nums[i] <= 10^4` // - `nums` 中的每个值都 独一无二 // - 题目数据保证 `nums` 在预先未知的某个下标上进行了旋转 // - `-10^4 <= target <= 10^4` // search 在旋转升序数组中查找 target,返回下标或 -1。 // // 思路:一次二分,不需要先找旋转点。 // 取 mid 后,[lo, mid] 和 [mid, hi] 必有一半是有序的: // - 若 nums[lo] <= nums[mid],左半有序;判断 target 是否落在 [nums[lo], nums[mid]], // 是则搜左半,否则搜右半。 // - 否则右半有序;判断 target 是否落在 [nums[mid], nums[hi]], // 是则搜右半,否则搜左半。 // // 时间 O(log n),空间 O(1)。 func search(nums []int, target int) int { lo, hi := 0, len(nums)-1 for lo <= hi { mid := lo + (hi-lo)/2 if nums[mid] == target { return mid } // 左半 [lo, mid] 有序 if nums[lo] <= nums[mid] { if nums[lo] <= target && target < nums[mid] { hi = mid - 1 } else { lo = mid + 1 } } else { // 右半 [mid, hi] 有序 if nums[mid] < target && target <= nums[hi] { lo = mid + 1 } else { hi = mid - 1 } } } return -1 } func TestSearch(t *testing.T) { cases := []struct { name string nums []int target int want int }{ {"example1", []int{4, 5, 6, 7, 0, 1, 2}, 0, 4}, {"example2", []int{4, 5, 6, 7, 0, 1, 2}, 3, -1}, {"example3", []int{1}, 0, -1}, {"example4", []int{1}, 1, 0}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { got := search(c.nums, c.target) if got != c.want { t.Errorf("got %v, want %v", got, c.want) } }) } }