概念引入
旋转排序数组 就是一个递增数组(暂且不论严格/非严格)在某一个点处进行了旋转。
为了避免“旋转”这个词的歧义,下面用一个例子直观展示:
原递增数组:[1, 2, 3, 4, 5, 6, 7]
旋转后数组:[4, 5, 6, 7, 1, 2, 3]
性质分析
第一点:旋转多次等价于旋转一次
不要被“旋转”这两个字误导,透过现象看本质,所谓的 旋转 其实就是 循环移动 —— 你看成循环左移/循环右移都可以,本质还是 模(mod)。
在纸上写写画画,比凭空想象有用。
第二点:变换后的数组仍保留着部分有序性
由于多次变换等价于一次变换,所以不管数组“旋转”了多少次,最后还是等价于“旋转”了一次——变为了两段递增序列。
这种尚未完全消失的递增性质,也是下面我们依旧可以使用二分的前提。
图解二分
这类题目的关键技巧是:以右端点 nums[right] 为基准,作为二分减治的依据。
假设原数组严格递增(不存在重复),根据下面两种情况进行二分减治:
假设原数组非严格递增(存在重复数字),那么我们无从判断是下面的哪一种情况,解决的方案是从右侧开始收缩重复元素(反正存在重复,起码nums[mid]==nums[right],所以可以放心收缩掉):
题目1. 寻找旋转数组中的最小值
假设原数组严格递增(不存在重复)
class Solution {
public int findMin(int[] nums) {
int left = 0;
int right = nums.length - 1;
int mid;
while (left < right) {
mid = left + (right - left) / 2;
if (nums[mid] > nums[right]) {
left = mid + 1;
} else {
right = mid;
}
}
return nums[left];
}