博客
关于我
算法笔记_128:完美洗牌算法(Java)
阅读量:435 次
发布时间:2019-03-06

本文共 3100 字,大约阅读时间需要 10 分钟。

目录

 


1 问题描述

有一个长度为2n的数组{a1,a2,a3,...,an,b1,b2,b3,...,bn},希望排序后变成{a1,b1,a2,b2,a3,b3,...,an,bn},请考虑有没有时间复杂度为O(n)而空间复杂度为O(1)的解法。

 

 


2 解决方案

2.1位置置换算法

下面算法的时间复杂度为O(n),空间复杂度为O(n)

具体代码如下:

package com.liuzhen.practice;public class Main {    //对于数组A第i个位置的元素都最终换到了2*i % len的位置    public void getLocationReplace(String[] A) {        int len = A.length;        String[] temp = new String[len];        for(int i = 1;i < len;i++)            temp[(2 * i) % len] = A[i];        for(int i = 1;i < len;i++)            A[i] = temp[i];        for(int i = 1;i < len;i = i + 2) {            String a1 = A[i];            A[i] = A[i + 1];            A[i + 1] = a1;        }        return;    }            public static void main(String[] args) {        Main test = new Main();        String[] A = {"", "a1", "a2", "a3", "a4", "a5", "b1", "b2", "b3", "b4", "b5"};        test.getLocationReplace(A);        for(int i = 1;i < A.length;i++)            System.out.print(A[i]+" ");    }}

 

运行结果:

a1 b1 a2 b2 a3 b3 a4 b4 a5 b5

 

 

2.2 走环算法

下面算法的时间复杂度为O(n),空间复杂度为O(1)

具体代码如下:

package com.liuzhen.practice;public class Main1 {        public void CycleLeader(String[] A, int start, int mod) {        for(int i = start * 2 % mod;i != start;i = i * 2 % mod) {            String temp = A[i];            A[i] = A[start];            A[start] = temp;        }        return;    }        public void Reverse(String[] A, int start, int end) {        while(start < end) {            String temp = A[start];            A[start++] = A[end];            A[end--] = temp;        }        return;    }        public void RightRotate(String[] A, int start, int m, int n) {        Reverse(A, start + m + 1, start + n);        Reverse(A, start + n + 1, start + n + m);        Reverse(A, start + m + 1, start + n + m);        return;    }        public void PerfectShuffle(String[] A) {        int len = A.length;        int n = (len - 1) / 2;        int start = 0;        while(n > 1) {            //第1步:找到2*m = 3^k - 1,使得3^k <= len - 1 < 3^(k + 1)            int k = 0, m = 1;            for(;(len - 1) / m >= 3;k++, m = m * 3);            m = m / 2;                    //第2步:把数组中的A[m + 1,...,n + m]那部分循环右移m位            RightRotate(A, start, m, n);                        //第3步:对于长度为2*m的数组,刚好有k个圈,每个圈的头部为3^i            for(int i = 0, t = 1;i < k;i++, t = t * 3)                CycleLeader(A, t, m * 2 + 1);                        //第4步:对数组后面部分A[2m + 1,...,2n]继续递归上面3步            start = start + m * 2;            n = n - m;                    }        //n == 1时        String temp = A[1 + start];        A[1 + start] = A[2 + start];        A[2 + start] = temp;        for(int i = 1;i < len;i = i + 2) {            String a1 = A[i];            A[i] = A[i + 1];            A[i + 1] = a1;        }        return;    }        public static void main(String[] args) {        Main1 test = new Main1();        String[] A = {"", "a1", "a2", "a3", "a4", "a5", "b1", "b2", "b3", "b4", "b5"};        test.PerfectShuffle(A);        for(int i = 1;i < A.length;i++)            System.out.print(A[i]+" ");    }}

 

运行结果:

a1 b1 a2 b2 a3 b3 a4 b4 a5 b5

 

 

 

参考资料:

   1.《编程之法面试和算法心得》  July

转载地址:http://brvyz.baihongyu.com/

你可能感兴趣的文章
mysql解压没有data_Windows 64 位 mysql 5.7以上版本包解压中没有data目录和my-default.ini及服务无法启动的快速解决办法(问题小结)...
查看>>
Mysql解压版安装
查看>>
Mysql设置字符编码及varchar宽度问题
查看>>
MySQL设置白名单限制
查看>>
MySQL设置远程连接
查看>>
MySQL详解:索引的介绍和原理分析
查看>>
MYSQL语句。
查看>>
MySQL调大sort_buffer_size,并发量一大,查询排序为啥又会变慢
查看>>
Mysql账号权限查询(grants)
查看>>
MYSQL输入密码后闪退的解决方法
查看>>
MySQL迁移到达梦:如何轻松、高质量完成迁移任务
查看>>
mysql返回的时间和实际数据存储的时间有误差(java+mysql)
查看>>
mysql还有哪些自带的函数呢?别到处找了,看这个就够了。
查看>>
Mysql进入数据库
查看>>
mysql进阶 with-as 性能调优
查看>>
mysql进阶-查询优化-慢查询日志
查看>>
wargame narnia writeup
查看>>
MySQL进阶篇SQL优化(InnoDB锁问题排查与解决)
查看>>
Mysql进阶索引篇03——2个新特性,11+7条设计原则教你创建索引
查看>>
Mysql连接时报时区错误
查看>>