1. 旋转数组的定义
这里参考 leetcode 189
这题可以有多种方式进行求解
这里给出原地旋转的方法,见下图:
代码:
public void rotate(int[] nums, int k) {
if (nums == null || nums.length <= 1){
return ;
}
int len = nums.length;
k = k%len;
if (k == 0){
return;
}
reverse(nums,0,len-1);
reverse(nums, 0, k - 1);
reverse(nums, k, nums.length - 1);
}
public void reverse(int nums[], int l, int r){
if (l>r){
return;
}
for (int i = l; i <= (l+r)>>1 ; i++) {
swap(nums,i,r-(i-l));
}
}
public void swap(int nums[], int i, int j){
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
2. 在旋转排序数组中查找值
这里必须加个限制条件:
时间复杂度为 :O(log2N)
2.1 不存在重复的元素
参考题目:Leetcode 33
这里考虑使用二分方法:
变量定义:
int l; //二分查找的左边界
int r; // 二分查找的右边界
int mid; //二分查找的中间
旋转排序数组的草图如下:
二分查找的过程:
- 如果
nums[mid] == target
, 返回true
- 如果
nums[l] < nums[mid]
,此时需要分情况讨论:nums[l] <= target < nums[mid]
:target
在左边的递增区域,则r = mid - 1
;- 不然,搜索右区域;
- 如果(2)不成立,则说明右侧为递增区域,进行如下讨论
num[mid] < target <= nums[r]
:target
在右边的递增区域,则l = mid + 1
;- 不然对左边区域进行搜索;
代码:
public int search(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return -1;
}
int l = 0;
int r = nums.length-1;
while(l<=r) {
int mid = (l+r)/2;
// 流程 1
if (nums[mid] == target) {
return mid;
}
//流程 2
if (nums[l] <= nums[mid]) {
if (target >= nums[l] && target < nums[mid]) {
r = mid-1;
}else {
l = mid + 1;
}
}else
// 流程 3
{
if (target > nums[mid] && target <= nums[r]) {
l = mid+1;
}else {
r = mid-1;
}
}
}
return -1;
}
2.2 存在重复元素
参考题目: leetcode 81
与上面一题的方法相似
我们需要进行如下思考:
10111
此种情况下 nums[l] == nums[mid]
,分不清到底是前面有序还是后面有序,此时 需要设置 i++
即可。相当于去掉一个重复的干扰项。
代码:(大体相似,只需要进行上面的操作)
public boolean search(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return false;
}
int l = 0;
int r = nums.length-1;
while(l<=r) {
int mid = (l+r)/2;
if (nums[mid] == target) {
return true;
}
// 只需要改变这里
if (nums[mid] == nums[l]) {
l++;
}
else if (nums[l]<nums[mid]){
if (nums[l]<= target && target < nums[mid]) {
r = mid-1;
}else {
l = mid+1;
}
}else {
if (nums[mid]<target && target <= nums[r]) {
l = mid+1;
}else {
r = mid-1;
}
}
}
return false;
}
3. 在旋转排序数组中查找最小值
参考例题 : Leetcode 153
算法流程(二分查找):
-
如果
num[mid] > nums[r]
,说明最小值在右区间,l = mid + 1
-
否则需要往左进行查找,
r = mid
注意:这里 右边界不是
mid-1
的原因是,mid
位置的元素可能是最小值
代码:
public int findMin(int[] nums) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = (right + left) / 2;
if (nums[mid] > nums[right]) {
left = mid + 1;
} else {
right = mid;
}
}
return nums[left];
}