基础算法篇-旋转数组

基础算法篇

LeetCode刷题打卡第3天 2022.12.3

旋转数组

题目链接

题目描述

给你一个数组nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

  • 尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。
  • 你可以使用空间复杂度为 O(1)原地 算法解决这个问题吗?

输入示例

示例一

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]

示例二

输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释: 
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]

数据范围

  • 1 <= nums.length <= 105
  • -231 <= nums[i] <= 231 - 1
  • 0 <= k <= 105

解题思路

思路一 使用额外数组辅助

创建辅助数组tempArray,循环原数组nums的长度len = nums.length 次,将原数组 nums[(i + k) % len] 的值赋给tempArray[i],完成后,再将tempArray数组的值依次赋给nums

Java代码实现
class Solution1 {
    //使用额外数组
    public void rotate(int[] nums, int k) {
        int len = nums.length;
        k = k % len;
        if (len <=1 || k <= 0){
            return;
        }
        int[] tempArray = new int[len];
        int tempi;
        for (int i = 0; i < len; i++) {
            tempi = (i + k) % len;
            tempArray[tempi] = nums[i];
        }
        for (int i = 0; i < nums.length; i++){
            nums[i] = tempArray[i];
        }
    }
}

思路二 环状替换

举例如下:

nums = [1,2,3,4,5,6]
k = 2

环状替换例子图

每单圈替换过程:用start表示第一个数的下标,用current表示当前正要发生替换数的下标,currentNum表示正要用于替换的数,next表示将要被替换的数的下标,nextNum表示将要被替换的数的副本,对于图中:start = 0,current = 0,currentNum = 1, next = 2,nextNum = 3。本次替换过程如下:

步骤1

步骤2

步骤2

每圈替换当再一次current == start 时,本圈结束,下一圈的start++,最终当替换次数cout >= len 时结束。

Java实现代码
class Solution {
    // 环状替换
    public void rotate(int[] nums, int k) {
        int len = nums.length;
        k = k % len;
        if (len <=1 || k <= 0){
            return;
        }
        int cout = 0;
        int start = -1;
        while (cout < len) {
            start++;
            int current = start;
            int currentNum = nums[current];
            int nextNum = nums[(current + k) % len];
            do {
                int next = (current + k) % len;
                nums[next] = currentNum;
                currentNum = nextNum;
                nextNum = nums[(next + k) % len];
                current = next;
                cout++;
            } while (current != start);
        }
    }
}

思路三 数组翻转

  1. 先全部反转,将元素提到最前面
  2. 反转前半部分(k 到 len-1)
  3. 反转后半部分(0 到 k-1)
    然后返回结果

题解图

借用LeetCode美服dalao的形象解释 原链接

nums = "----->-->"; k =3
result = "-->----->";

reverse "----->-->" we can get "<--<-----"
reverse "<--" we can get "--><-----"
reverse "<-----" we can get "-->----->"
this visualization help me figure it out :)
Java代码实现
class Solution {
    // 数组翻转
    public void rotate(int[] nums, int k) {
        int len = nums.length;
        k = k % len;
        if (len <=1 || k <= 0){
            return;
        }
        int temp;
        for (int i = 0; i < len/2; i++) {
            mySwap(nums, i, len - 1 - i);
        }
        for (int i = 0; i < k/2; i++) {
            mySwap(nums, i, k - 1 - i);
        }
        for (int i = 0; i < (len - k) / 2; i++) {
            mySwap(nums, k+i, len - 1 - i);
        }
    }
    private void mySwap(int[] nums, int i, int j) {
        int temp = nums[j];
        nums[j] = nums[i];
        nums[i] = temp;
    }
}
posted @ 2022-12-03 21:46  FREAM  阅读(76)  评论(0)    收藏  举报