旋转数组(Leetcode刷题c++)

题目
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

示例 1:
输入: [1,2,3,4,5,6,7] 和 k = 3
输出: [5,6,7,1,2,3,4]
移动过程:
1.向右旋转 1 步: [7,1,2,3,4,5,6]
2.向右旋转 2 步: [6,7,1,2,3,4,5]
3.向右旋转 3 步: [5,6,7,1,2,3,4]

示例 2:
输入: [-1,-100,3,99] 和 k = 2
输出: [3,99,-1,-100]
移动过程:
1.向右旋转 1 步: [99,-1,-100,3]
2.向右旋转 2 步: [3,99,-1,-100]
说明:
1.尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
2.要求使用空间复杂度为 O(1) 的 原地 算法。

题目分析
该题的目的是按照步数来向右移动整个数组的元素位置。如果不加说明里面第二条空间复杂度为 O(1) 的限制,该题很容易解决,直接另外新建一个同大的数组来保存移动的数据即可快速解决。但有了这个限制之后,编程时就需要考虑程序内存的问题。该题的解决方法多种多样,这里我将详细介绍我在刷这题时的思路。
第一步:由于传递进入函数的k(步数)值取值没有限制,因此,需要考虑如何最快根据k来确定移动步数。举个例子,假设数组为{1,2,3,4,5,6},如果给定k为10000,我们难道要真的移动10000次吗?显然是不可能这样做的。这里之所以可以快速确定实际的移动步数是因为数组的大小是固定的,当k值等于数组大小时,里面的元素移动后正好和原来一样,相当于没有移动。因此,无论k值多大,我们实际上只要进行一次的数组元素移动即可。以示例1为例,数组大小为7,任取k值,实际上只要用k对7取余即可。因此实际移动步数=k%7。
第二步:考虑根据移动步数来确定原数组每个元素移动后的新位置。由于第一步已经确定移动步数,因此,新位置很容易确定,将原位置下标加上移动步数即可。但这里要考虑下新位置的越界情况。
第三步:有了前两步,对于给定下标的数组元素,我们能直接得到它移动后的位置。因此,首先将数组元素和新位置上原来的数值进行交换,然后记住刚刚新的位置,计算该位置移动后的新位置,并将该位置原来的数值(已经不在该位置上,因为之前已经交换了)和新位置上的数值进行交换,循环下去,直到数组所有元素都移动完为止。该过程如下图(以示例1为例):先移动最后一个元素7,首先计算该元素的新位置下标为2,因此将该位置与下标为2的位置上的元素3互换。此时计算元素3的最终位置为5,因此将元素3与下标为5的元素6互换。然后再计算元素6的最终位置为1,因此将元素6与下标为1的元素2互换。接下来计算元素2的最终位置为4,因此将元素2与下标为4的元素5互换。继续计算元素5的最终位置为0,因此将元素5与下标为0的元素1互换。最后计算元素1的最终位置为3,将1与下标为3的元素4互换得到最终的移动结果。
在这里插入图片描述

从图中可以看出来,对于示例的数组来说,完成移动只需要六次的交换会即可。对于大小为n的数组,完成移动只需要n-1次交换。

Leetcode测试代码如下:

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int lenth = nums.size();
        int move = k%lenth;//移动步数
        if(move%lenth!=0){
            int i = 0;//计数器
        int start = lenth-1;//第一个移动的元素位置,一开始设置为最后一个元素,后面保持不变用来保存位置被取代的数
        int end = start+move-lenth;//每次将要移动的新位置
        int temp=0;//保存位置被取代的数
        while(i<lenth-1)  //只需要lenth-1次交换
        {
            temp = nums[end];
            nums[end] = nums[start];
            nums[start] = temp;
            if(end+move<=lenth-1)
                end = end+move;   //更新下一个新的位置
            else 
                end = end+move-lenth;
            if(end==start){
                i++;
                start--;
                end = start+move-lenth;
            }
            i++;
        }   
        }
        
    }
};

运行结果如下:
在这里插入图片描述

VS下完整代码如下:

#include<iostream>
#include<vector>

using namespace std;

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int lenth = nums.size();
        int move = k%lenth;//移动步数
        if(move%lenth!=0){
            int i = 0;//计数器
        int start = lenth-1;//第一个移动的元素位置,一开始设置为最后一个元素,后面保持不变用来保存位置被取代的数
        int end = start+move-lenth;//每次将要移动的新位置
        int temp=0;//保存位置被取代的数
        while(i<lenth-1)  //只需要lenth-1次交换
        {
            temp = nums[end];
            nums[end] = nums[start];
            nums[start] = temp;
            if(end+move<=lenth-1)
                end = end+move;   //更新下一个新的位置
            else 
                end = end+move-lenth;
            if(end==start){
                i++;
                start--;
                end = start+move-lenth;
            }
            i++;
        }   
        }
        
    }
};


int main()
{
    vector<int> A={1,2,3,4,5,6,7};
    int k=3;
    Solution object;
    object.rotate(A,k);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Inthesilence/article/details/104783323