LeetCode189 Rotate Array

LeetCode189 Rotate Array

最近重新开始刷题了! 因为之前写过的错题总是一错再错,想找个地方总结一下错题,方便之后回忆思路!

题目

Link: https://leetcode.com/problems/rotate-array/
Given an array, rotate the array to the right by k steps, where k is non-negative.

Example1:
Input: nums = [1,2,3,4,5,6,7], k = 3
Output: [5,6,7,1,2,3,4]
Explanation:
rotate 1 steps to the right: [7,1,2,3,4,5,6]
rotate 2 steps to the right: [6,7,1,2,3,4,5]
rotate 3 steps to the right: [5,6,7,1,2,3,4]

Example2:
Input: nums = [-1,-100,3,99], k = 2
Output: [3,99,-1,-100]
Explanation:
rotate 1 steps to the right: [99,-1,-100,3]
rotate 2 steps to the right: [3,99,-1,-100]

思路

一开始想的是把 nums 分成 k 组 ( i % len = 0, i % len = 1 … i % len = k-1, len = nums.length), 然后按组更新nums。 后来发现因为这是一个rotate array, 每移动 k steps 不一定只会走到 i % len 相同的地方。

比如说,nums = [1,2,3,4,5,6,7],k = 3。
按最开始想的分组应该是:
i % len = 0 : 1 -> 4 -> 7
i % len = 1 : -> 2 -> 5
i % len = 2 : -> 3 -> 6
但实际模拟一下移动 k steps 的情景,发现是:
1 -> 4 -> 7 -> 3 -> 6 -> 2 -> 5

觉得大致思路应该没什么问题,但是卡在了怎么排除已经改变过的那些数组元素。 试了好多种方法都有bug, 直到搜到一篇博文:
https://blog.csdn.net/qq_28584889/article/details/83655019
才发现用一个count来统计已经改变过的元素数量,跟数组长度比较,来决定是否跳出循环就可以了!

随后我又想到了一个问题:我是按 i % len 的分组从小到大循环的,当count < nums.length 的时候,要怎么知道我接下来按顺序的这个分组是没有被改变过的呢?

有点不知道怎么解释,举个例子吧:现在有k个分组( 0 到 k-1),从0组第一个元素开始改元素。 如果0组的最后一个元素改完之后是跳到1组第一个元素, 那么1组最后一个元素改完之后一定会跳到2组第一个元素; 如果0组最后一个元素改完之后跳到2组第一个元素, 那么2组最后一个元素改完之后一定会跳到4组第一个元素,当跳回0组第一个元素之后, 我们就该换下一组。 下一组就是1组->3组->5组这个顺序。所以,接下来按顺序的这个分组一定是没有被改变过的。

上代码

public void rotate(int[] nums, int k) {
        
        if(nums == null || nums.length < 2 || k == 0|| k== nums.length) {
            return;
        }
        k = k % nums.length;
        int count = 0;
        for(int i = 0; i < k; i++) {
            //可以按顺序 因为如果 i+1被命中了那i+2一定会在同一轮被命中 
            if(count == nums.length) {
                break;
            }
            int next = (i + k) % nums.length;
            int prev = nums[i]; //需要一个变量来保存放在next位置的元素 因为每次被替换掉的nums[next]都是下一个next需要存放的元素
            while(next != i) {
                int temp = nums[next];
                nums[next] = prev;
                prev = temp;
                next = (next + k) % nums.length;
                count ++;
            }
            nums[next] = prev;
            count++;
        }
    }

时间复杂度 O(n), 空间复杂度 O(1)

Using Reverse

在LeetCode Solution里看到了用reverse的做法也挺妙的。 感觉做题的时候还是应该多观察规律呀!

大概记录一下:
nums = [1, 2, 3, 4, 5, 6, 7], k = 3
改变后的最终结果应该是:
nums = [5, 6, 7, 1, 2, 3, 4]
有点像把nums分成两组,直接后移的组(1, 2, 3, 4) 和需要rotate到开头的组(5, 6, 7)。把最后k个元素放到index = 0开始的地方, 把前(len - k)个元素往后移k个位置。
所以可以先把整个array翻转:
7, 6, 5, 4, 3, 2, 1
这步约等于把两个组放在应该放的地方,只不过组内元素顺序不对
然后分别把两个组的元素翻转,也就是把组内元素顺序复原
5, 6 ,7 || 1, 2, 3, 4

时间复杂度O(n), 空间复杂度O(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值