Java实现完美洗牌算法

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)。packagecom.liuzhen.practice;publiccl…

大家好,又见面了,我是你们的朋友全栈君。

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 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/126209.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Centos镜像国内最全下载地址

    Centos镜像国内最全下载地址这里写代码片CentOS7官方下载地址:https://www.centos.org/download/Centos国内下载源http://man.linuxde.net/download/CentOShttp://mirrors.btte.net/centos/7/isos/x86_64/http://mirrors.cn99.com/centos/7/isos/x86_64/h…

    2022年6月14日
    31
  • 按位取反计算_二进制按位取反怎么算

    按位取反计算_二进制按位取反怎么算(按位取反)运算的理解:按照我平时的理解,当我使用~按位取反运算的时候,计算机会将操作数所对应的二进制表达式的每一个位进行取反计算,取反后所得到的值就是~按位取反的运算结果(这点没问题)例如,假如我的计算机是32位的,我接下来要计算~5的值,计算过程如下:5的二进制表达式为:00000000000000000000000000000101执行~运算,即~5后:11…

    2022年8月15日
    9
  • java 滤波算法_双边滤波算法

    java 滤波算法_双边滤波算法1、原理高斯滤波是以距离为权重,设计滤波模板作为滤波系数,只考虑了像素间的空间位置上的关系,因此滤波的结果会丢失边缘的信息。高斯滤波的缺陷如下图所示:平坦区域正常滤波,图像细节没有变化,而在突变的边缘上,因为只使用了距离来确定滤波权重,导致边缘被模糊。在高斯基础上,进一步优化,叠加了像素值的考虑,因此也就引出了双边滤波,一种非线性滤波,滤波效果对保留边缘更有效。为了理解双边滤波的距离和像素差两个影…

    2022年5月29日
    37
  • 【转载】viewState详解

    【转载】viewState详解

    2021年11月21日
    55
  • Java实现 Hello World

    Java实现 Hello WorldHelloWorld记事本手写HelloWorldeclipse编辑器从零到一实现HelloWorld记事本手写HelloWorld1.新建Hello文本文件输入以下代码eclipse编辑器从零到一实现HelloWorld

    2022年7月16日
    15
  • 51单片机通过WIFI模块ESP8266控制LED灯

    51单片机通过WIFI模块ESP8266控制LED灯一 系统方案手机 APP 通过 ESP8266WIFI 模块与 51 单片机通信控制 LED 灯的开关 下位机由单片机 ESP8266 模块和 LED 灯组成 上位机由 Android 手机 APP 承担 我们在 APP 上发送 LED 灯的开关控制指令 ESP8266 将收到的数据发送给单片机 从而实现对 LED 灯进行开关控制 设计好的实物是这个样子 二 硬件设计 ESP8266 模块作为一个透传模块使用 RXD

    2025年7月11日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号