旋转数组问题“环状替换”解法最详细的说明

leecode“旋转数组”问题,“环状替换”解法的思路(小白向)

思路:
		假设一数组 a[1,2,3,4,5,6,7,8,9] 移动位数k=31开始,要将a[0]右移三位,移到a[3]
		a[3]右移三位,移到a[6]
		a[6]移到a[0]
		回到了a[0],我们不妨称这叫一个环路,这个环路的长度是一个数组的长度,按下标表示为0360,以元素来表示是1471。暂且抛去其他,我们看怎样实现一个环路:
		    如果只简单地令a[3]=a[0],那么数组变为a[1,2,3,1,5,6],此时出现问题,a[3]原本的值被覆盖丢失了。
		    于是我们先交换a[3]和a[0],数组变为a[4,2,3,1,5,6],这样交换完成后,原本a[3]的值被临时存储到a[0]中,
		    	而a[0]已经赋值给了a[3],所以值不会丢失。
		    接下来很简单,依次将剩下的非首元素的环路元素与a[0]交换。
		    具体到上面的0360,可以表述为,a[3]、a[6]依次与a[0]交换位置,整个环路就交换完成。
		 解决了一个环路内的元素如何旋转的问题,我们要知道这个数组到底有几个环路
             用数组b[1,2,3,4,5,6,7,8]来举例
             从元素1开始,很容易看出环路为147258361,
             然后看元素2,但元素2已经在元素1的环路中了,所以我们知道,此数组一共三个环路
             我们将环路遍历过程完整地写下来,为了更容易理解。如果右移超出了数组长度,我们将数组复制一份到右边
             (但这只是为了方便理解所做,真正的数组不变)
             1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
             1     4     7     2     5     8     3     6
             一共走过了三个数组的长度
             将环路中的每个元素与其后面的两个元素看为一个整体。如123是一个整体、456也是一个整体
             那么
             1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
             1     4     7     2     5     8     3     6
             |     |     |     |     |     |     |     |
             1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
             很容易看出:
             环路中元素的个数b*移动的位数k=数组的长度n*遍历走过的数组个数x 即bk=nx
             k、n是已知的。我们求出一个环路中元素的个数b,就可以求出环路个数x了。
             关键是x
             我们看,从元素1开始,以两个元素的间隔向后遍历,最终会回到元素1.那如果再向后遍历呢?
             1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
             1     4     7     2     5     8     3     6     1     4     7     2     5     8     3     6
             再向后遍历一个循环,还是一样会回到元素1,此时x=6。以此类推,当x=3 6 9 12....时,遍历一定还会回到元素1
             但是因为第一个环路已经遍历完了数组内的所有元素,以后的遍历会把已经遍历完的元素再遍历一遍,这是不需要的。
             所以我们取x的最小值。
             在bk=nx中
             n是固定的,所以我们要取nx的最小值。
             显然,nx可以被n、k整除且结果都大于0
             所以,nx是n、k的公倍数,又因为nx要取最小,所以
             bk=nx=nk的最小公倍数
             故 b=nk的最小公倍数/k
             每个环路遍历的元素是一样多的,且总和为数组长度n
             所以环路数x=n/b

代码:

public static int[] moveArray(int[] list,int k){
        int n=list.length;
        int x=n/(myMath.minMultiple(n,k)/k);
        for(int i=0;i<x;i++){
            int j=i,l=i;
            do{
                int h=((l+k)%n);
                int temp=list[j];;
                list[j]=list[h];
                list[h]=temp;
                l=h;
            }while (l!=j);
        }
        return list;
    }

以上

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值