旋转数组处理方法归纳

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;	//二分查找的中间

旋转排序数组的草图如下:

在这里插入图片描述

二分查找的过程:

  1. 如果 nums[mid] == target, 返回 true
  2. 如果 nums[l] < nums[mid],此时需要分情况讨论:
    • nums[l] <= target < nums[mid]target 在左边的递增区域,则 r = mid - 1;
    • 不然,搜索右区域;
  3. 如果(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

算法流程(二分查找):

  1. 如果 num[mid] > nums[r],说明最小值在右区间,l = mid + 1

  2. 否则需要往左进行查找,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];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值