题解 | #旋转数组#

旋转数组

https://www.nowcoder.com/practice/e19927a8fd5d477794dac67096862042

除了三次翻转以外的O(1)空间思路:一步旋转到位

如果m=1,用一个萝卜一个坑的想法,萝卜A移到B,B到C,最后一个萝卜放到A的坑,就结束了。可是m可能是任意值,一次循环做完不一定所有萝卜的坑位都换了,比如数组1-6要旋转2个单位,就会分别存在1 -> 3 -> 5 -> 1和2 -> 4 -> 6 -> 2的两个环。
既然可能存在多个环,那么不是可以像DFS算岛的数量一样,遍历完一个环就去下一个环吗?在岛屿遍历中,我们可以mark走过的点,但这题无法添加mark,而且只有O(1)空间所以也不能用额外的数据结构记录访问过的点。但这些环有一个性质,就是若存在多个环,那么每个环的起点是相邻的 (假设以0作为起点,若相邻的1也在同一个环内的话,说明在走了n圈之后,可以达到1,那么以此类推,再走n圈就能到达2。只要继续走,所有点都能在该环内遍历到)。所以只要知道环的数量,就可以顺序访问找到下一个环的一个点开始遍历。
环的数量是多少呢?我们知道一个环里是不可能有重复点的,且所有环的长度相同,所以环的数量为数字总数n除以一个环的长度length。
长度就很好计算了,先遍历一个环我们就知道环长了。最后实现代码如下:
import java.util.*;


public class Solution {
    /**
     * 旋转数组
     * @param n int整型 数组长度
     * @param m int整型 右移距离
     * @param a int整型一维数组 给定数组
     * @return int整型一维数组
     */
    public int[] solve (int n, int m, int[] a) {
        if ((m = m % n) == 0 || n < 2) {
            return a;
        }
        int circleLen = rotate(a, 0, m, n);
        int circleCount = n / circleLen;
        for (int i = 1; i < circleCount; i++) {
            rotate(a, i, m, n);
        }
        return a;
    }

    public int rotate(int[] a, int start, int m, int n) {
        int circleLen = 1;
        int cur = a[start];
        int next = start + m, nextVal;
        while (next != start) {
            circleLen++; // 统计环的长度+1
            nextVal = a[next]; // 把下一个数字B取出
            a[next] = cur; // 当前数字A占领B的位置
            cur = nextVal; // 拿着B
            next = (next + m) % n; // 找下一个位置C
        }
        a[start] = cur; // 最后剩下的数字放回环的起点
        return circleLen;
    }
}


#算法题#
全部评论

相关推荐

01-30 22:03
门头沟学院 Java
用微笑面对困难:我滴妈,【俩月】【实习】【主管】仨debuff吃满了,独立设计开发的项目写了绝大占比的运营板块,你独立开发,那维护、问题复盘、日志更新、bug、策划书全是自己整的? 不建议写那么大,可以从小出发更容易
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务