LeetCode每日一题(三)——【轮转数组】


问题描述:

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

示例 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]

原因分析:【这是大佬总结的,在这里谢谢小甜甜大佬】

  • 此题可以采用头插法,一个一个的移动。但是有种更加简单的选择数组的方式。
  • 我们可以采用翻转的方式,比如12345经过翻转就变成了54321,
  • 这样已经做到了把前面的数字放到后面去,但是还没有完全达到我们的要求,
  • 比如,我们只需要把12放在后面去,目标数组就是34512,与54321对比发现我们就只需要在把分界线前后数组再进行翻转一次就可得到目标数组了。
  • 所以此题只需要采取三次翻转的方式就可以得到目标数组:
  • 首先翻转分界线前后数组,再整体翻转一次即可。
  • 此题面试常考,大家可以记一下此方法。
  • 需要注意的是,本题还有一个小陷阱,题目输入中,如果k大于nums.size了应该怎么办?**

解决方案:

1.如果k大于nums.size了应该怎么办?

举个例子,比较容易想,

例如,1,2,3,4,5,6,7 如果右移动15次的话,是 7 1 2 3 4 5 6 。 

所以其实就是右移 k % nums.size() 次,即:15 % 7 = 1

 官方没有给出python的方法,因为在python中,列表的切片真的是太灵活了。

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        nums[: ] = (nums[i] for i in range(-(k % len(nums)), len(nums) - k % len(nums)))

这是大佬的代码。【优化后】

至于上述思路中的三次翻转,大佬只用了两次翻转。因为python对列表可以选取,所以不需要整体去翻转,只需要按照k值,截取移动长度,然后在拼接成一个,就可以。

【优化前的代码,理解起来也挺容易的】:

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        nums[: ] = nums[-k % len(nums): ] + nums[: -k % len(nums)]

至于为什么开头的nums要变为nums[ : ] ,是因为:

不写切片相当于nums修改的地址重新指向右边的临时地址,写切片相当于按着切片下标修改值,前者在线上判定里无法AC,线上判定只判定原地地址的情况,不写切片的nums只在函数内有效

 如果换成其他语言,就可以循规蹈矩,按照之前的分析做即可:

1、python【俺自己写的,比较垃圾】

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        if(len(nums)<2):
            return
        k = k%len(nums)-1
        nums[ : ] = nums[::-1]
        nums[ : ] = nums[k::-1]+nums[:k:-1]

2、 C++【大佬写的,侵删】

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        // 三次翻转搞定
        k = k % nums.size();
        reverse(nums.begin(), nums.begin() + nums.size() - k);
        reverse(nums.begin() + nums.size() - k, nums.end());
        reverse(nums.begin(), nums.end());
    }
};

3、Java 【大佬写的,侵删】

class Solution {
    private void reverse(int[] nums, int start, int end) {
        for (int i = start, j = end; i < j; i++, j--) {
            int temp = nums[j];
            nums[j] = nums[i];
            nums[i] = temp;
        }
    }
    public void rotate(int[] nums, int k) {
        int n = nums.length;
        k %= n;
        reverse(nums, 0, n - 1);
        reverse(nums, 0, k - 1);
        reverse(nums, k, n - 1);
    }
}

总结:

其实如果单纯用python自带的reverse函数做,其实和其他语言没有区别,

但是如果用python中的切片方法做,那么你得了解足够了解,不然很容易被弄糊涂【比如我】

感谢大佬们在Leecode中的精彩评论,感谢CSDN中各位大哥的博客。

这是一篇博客,让我了解和复习了python切片,十分感谢:

精密解析Python切片用法_weixin_44099558的博客-CSDN博客_python切片用法众所周知,我们可以通过索引值(或称下标)来查找序列类型(如字符串、列表、元组…)中的单个元素,那么,如果要获取一个索引区间的元素该怎么办呢?切片(slice)就是一种截取索引片段的技术,借助切片技术,我们可以十分灵活地处理序列类型的对象。通常来说,切片的作用就是截取序列对象,然而,对于非序列对象,我们是否有办法做到切片操作呢?在使用切片的过程中,有什么要点值得重视,又有什么底层原理值得关注呢?...https://blog.csdn.net/weixin_44099558/article/details/85764468

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pan_peter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值