• 算法笔记_128:完美洗牌算法(Java)


    目录

    1 问题描述

    2 解决方案

    2.1位置置换算法

    2.2 走环算法

     


    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

  • 相关阅读:
    SpringMVC Failed to instantiate [java.util.List]: Specified class is an interface
    github上项目直接在浏览器页面像VS Code一样查看代码
    springboot+dubbo整合swagger-ui+swagger-dubbo
    petalinux非离线模式build卡死在u-boot编译问题
    SystemC使用示例
    使用chisel做数字电路开发的Hello World
    lmgrd在Linux系统上的配置
    FFmpeg libswscale源码分析3-scale滤镜源码分析
    FFmpeg libswscale源码分析2-转码命令行与滤镜图
    FFmpeg libswscale源码分析1-API介绍
  • 原文地址:https://www.cnblogs.com/liuzhen1995/p/6710029.html
Copyright © 2020-2023  润新知