u
This commit is contained in:
@@ -1,43 +1,84 @@
|
||||
package top100liked
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
import "testing"
|
||||
|
||||
// https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/?envType=study-plan-v2&envId=top-100-liked
|
||||
// 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`
|
||||
|
||||
func findMin(nums []int) int {
|
||||
if len(nums) == 1 {
|
||||
return nums[0]
|
||||
}
|
||||
if nums[0] < nums[len(nums)-1] {
|
||||
return nums[0]
|
||||
}
|
||||
|
||||
start := 0
|
||||
end := len(nums) - 1
|
||||
for start <= end {
|
||||
mid := start + (end-start)/2
|
||||
if mid >= 1 && nums[mid-1] > nums[mid] && mid < len(nums)-1 && nums[mid] < nums[mid+1] {
|
||||
return nums[mid]
|
||||
// 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
|
||||
}
|
||||
if nums[mid] > nums[end] {
|
||||
// 最小值在右侧
|
||||
start = mid + 1
|
||||
} else {
|
||||
// 最小值在左侧
|
||||
end = mid - 1
|
||||
// 左半 [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
|
||||
}
|
||||
}
|
||||
}
|
||||
if nums[start] > nums[end] {
|
||||
return nums[end]
|
||||
}
|
||||
return nums[start]
|
||||
return -1
|
||||
}
|
||||
|
||||
func Test(t *testing.T) {
|
||||
// fmt.Println(findMin([]int{3, 4, 5, 1, 2}))
|
||||
// fmt.Println(findMin([]int{3, 1, 2}))
|
||||
fmt.Println(findMin([]int{2, 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user