数组:数组旋转(对于环状替换有自认为比较详细的解释)

旋转数组

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/problems/rotate-array
来源:力扣(LeetCode)

题目描述:

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

示例 1:

输入: [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]

解题思路说明:

只针对自己看过一遍没有理解的算法进行简单说明:

方法3:使用环状替换

当时这个方法想了好几天,都没有理解,最后在网上看到大佬通过多边形讲解,感觉自己突然悟了。

使用此方法有两种情况:

  • case 1:数组为[1, 2, 3, 4, 5], k = 2;

    此时正确答案为4 5 1 2 3,对应的索引index改变顺序为1->3->5->2->4->1,为了方便写代码,可以看作index从1转了一圈,回到了起始位置,即此时index % n == 1,其中n为数组元素个数.我们用五边形的顶点表示数组中的元素,五边形如下图所示:

在这里插入图片描述

  • case 2:数组为[1, 2, 3, 4, 5, 6],如果继续按照上述方法,从第一个元素开始,索引index每次+k,则会出现1->3->5->1,此时循环已经结束,但是我们才交换了一半元素。解决方法也很简单,将初始的index+1,继续循环一遍,此时循环过程为2->4->6->2,其余的元素也被遍历了。不难看出,第一次循环终止的条件依旧是index % n == 1,第二次为index % n == 2。从而可以新加一个变量start表示index开始的位置,内循环开始位置为start,内循环终止条件改为index % n == start,每次内循环结束后,start加一。在内循环过程中,使用count变量记录交换次数,程序结束的条件为count>=n.雾霾用六边形的顶点表示数组中的元素,如下所示:

    在这里插入图片描述

    如果大家不能理解这个算法,可以跟着6变形的边走一遍。

方法4:使用反转

这个方法基于这个事实:当我们旋转数组 k 次, k%n个尾部元素会被移动到头部,剩下的元素会被向后移动。

答案v1.0

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        // 方法1:暴力反转,超出时间限制
        /*int temp = 0;
        int preEle = 0;
        for (int i = 0; i < k; i++)
        {
            preEle = nums[nums.size() - 1];
            for (int j = 0; j < nums.size(); j++)
            {
                temp = nums[j];
                nums[j] = preEle;
                preEle = temp;
            }
        }*/

        // 方法2:使用新的数组
        // 1. 使用push_back()实现。
        /*vector<int> temp;
        k = k % nums.size();
        for (int i = nums.size() - k; i < nums.size(); i++)
        {
            temp.push_back(nums[i]);
        }
        for(int i = 0; i < nums.size() - k; i++)
        {
            temp.push_back(nums[i]);
        }
        for (int i = 0; i < nums.size(); i++)
        {
            nums[i] = temp[i];
        }*/
        // 2,使用循环索引a
        /*vector<int> temp;
        k = k % nums.size();
        for (int i = 0; i < nums.size(); i++)
        {
            temp.push_back(nums[(i + nums.size() - k) % nums.size()]);
        }
        for (int i = 0; i < nums.size(); i++)
        {
            nums[i] = temp[i];
        }*/
        // 2,使用循环索引b
        /*vector<int> temp(nums.size(), 0);
        k = k % nums.size();
        for (int i = 0; i < nums.size(); i++)
        {
            temp[(i + k) % nums.size()] = nums[i];
        }
        for (int i = 0; i < nums.size(); i++)
        {
            nums[i] = temp[i];
        }*/
        // 3.使用环状替换
        /*int count = 0; //交换元素的次数
        int index = 0;//开始元素的位置
        k = k % nums.size();
        while (count < nums.size())
        {
            int preEle = nums[index];
            for (int i = index + k; i %  nums.size() != index; i += k)
            {
                int temp = nums[i %  nums.size()];
                nums[i %  nums.size()] = preEle;
                preEle = temp;
                count++;
            }
            nums[index] = preEle;
            count++;
            index++;
        }
        */
        // 方法4:使用反转
        k = k % nums.size();
        reverse(nums.begin(), nums.end()); //第一次翻转,翻转所有元素
        reverse(nums.begin(), nums.begin() + k);//翻转前k个元素
        reverse(nums.begin() + k, nums.end());// 翻转后面n - k个元素

    }
};
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值