`
爱宝贝丶
  • 浏览: 7178 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

使用三种方法求解前N个正整数的排列

阅读更多

       本篇博文给大家介绍前N个正整数的排列求解的三种方式。第一种是暴力求解法;第二种则另外声明了一个长度为N的数组,并且将已经排列过的数字保存其中;第三种方式则采用了另外一种思路,即首先获取N个整数的升序排列,然后对其位置进行随机交换以达到前N个整数的随机排列的目的。首先我们来看看第一种方式,具体代码如下:

import java.util.Random;

import org.junit.Test;

public class App {
  private int n = 100000;
  @Test
  public void testFirst() {
    int[] arr = new int[n];
    long start = System.currentTimeMillis();
    for (int i = 0; i < n; i++) {
      arr[i] = readInt(1, n + 1);
      while (isExist(arr, i)) {
        arr[i] = readInt(1, n + 1);
      }
    }
    long end = System.currentTimeMillis();
    System.out.println("方法一消耗时长为:" + (end - start));
  }

  private boolean isExist(int[] arr, int index) {
    for (int i = 0; i < index; i++) {
      if (arr[i] == arr[index]) {
        return true;
      }
    }
    return false;
  }

  private int readInt(int i, int j) {
    Random random = new Random();
    int result = random.nextInt(j);
    while (result < i) {
      result = random.nextInt(j);
    }
    return result;
  }
}

       这里输出结果如下

方法一消耗时长为:38580

        即当n为100000的时候,计算结果需要38.580s。该算法通过readInt(int i, int j)方法获取一个大于等于i并且小于等于j的整数,通过isExist(int[] arr, int index)方法判断数组中在索引为index之前的序列里是否已经存在了索引为index对应的值。该算法求解的思路即为从0开始对数组arr赋值,并且在每次获取一个随机数之后判断数组之前的部分中是否已经存在了该值,若存在了该值则继续获取,直至数组之前的部分中不存在该值。这种算法将产生大量的重复计算,主要来源在于判断数组之前的部分中是否存在该值和对于新的数组元素的获取两个部分。为了解决第一个问题,即判断数组之前部分中是否存在该值,我们采用了第二种算法,具体代码如下:

import java.util.Random;

import org.junit.Test;

public class App {
  private int n = 100000;

  @Test
  public void testSecond() {
    int[] arr = new int[n];
    long start = System.currentTimeMillis();
    boolean[] used = new boolean[n];
    for (int i = 0; i < n; i++) {
      arr[i] = readInt(1, n + 1);
      while (used[arr[i] - 1]) {
        arr[i] = readInt(1, n + 1);
      }
      used[arr[i] - 1] = true;
    }
    long end = System.currentTimeMillis();
    System.out.println("方法二消耗时长为:" + (end - start));
  }

  private int readInt(int i, int j) {
    Random random = new Random();
    int result = random.nextInt(j);
    while (result < i) {
      result = random.nextInt(j);
    }
    return result;
  }
}

        计算结果如下:

方法二消耗时长为:148

        若将N改为1000000,计算结果为:1.648s,若将N改为10000000,计算结果为33.679s,可以看出,该算法相对于第一种算法有所改进,但是对于千万级数据量的处理消耗时长较长。第二种算法另外声明了一个数组used,该数组长度为N,这里将要求解的数据(长度为N的正整数的排列)与used数组的下标形成一种一一对应的关系,当要判断某个获取到的正整数是否已经存在时,只需要判断数组中对应下标的数据值是否为true,为true则表示已经存在。但是这里经过我们的分析也会发现,对于采用readInt(int i, int j)方法获取新数据时,若该数据非常靠后,那么获取的难度(循环的次数)将会大大增加,这里也会影响该算法的运行效率。为了避免这个问题,我们则可以采用第三种方法,该方法则使用了一个已知的事实,即结果数组中的数值我们是完全确定的,变化的只是该数值的顺序,因而,我们如果采用随机算法改变各个数值的位置,即可达到排列各个数值的目的。具体的算法如下:

import java.util.Random;

import org.junit.Test;

public class App {
  private int n = 10000000;

  @Test
  public void testThird() {
    int[] arr = new int[n];
    long start = System.currentTimeMillis();
    for (int i = 0; i < n; i++) {
      arr[i] = i + 1;
    }
    for (int i = 1; i < n; i++) {
      swapReferences(arr, i, readInt(0, i));
    }
    long end = System.currentTimeMillis();
    System.out.println("方法三消耗时长为:" + (end - start));
  }

  private void swapReferences(int[] arr, int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
  }

  private int readInt(int i, int j) {
    Random random = new Random();
    int result = random.nextInt(j);
    while (result < i) {
      result = random.nextInt(j);
    }
    return result;
  }
}

       运行结果如下:

方法三消耗时长为:2105

       该方法通过readInt(int i, int j)方法每次获取数组中索引为0到索引为i的随机索引,将并且将数组中索引为i的数据与获取到的索引对应的数据位置替换,这样就可以达到全排列的目的。

分享到:
评论

相关推荐

    问题描述:求从1~n的正整数中取出k(k<=n)个不重复整数的所有组合.pdf

    分析:求解k个数的不同组合,我们可以用一维数组a[0]~a[k-1]来保存其中的一个结果,因为组合元 素是不重复的,可以约定其递增排列,因为数组中的元素是递增排列的: 所以a[k-1]即组合中的最后一个数,只能为k~n 令i=...

    ACM算法竞赛中第二类斯特林数O(n^2)求解代码

    给定一个正整数 n,表示要划分的物体的数量,以及一个正整数 k,表示要划分成的循环排列的数量,第二类斯特林数 S(n, k) 表示将这 n 个物体划分成 k 个非空循环排列的方法数。 第二类斯特林数满足以下递推关系: S...

    计算机中的第二类斯特林数“同一行求解”的C++代码实现

    给定一个正整数 n,表示要划分的物体的数量,以及一个正整数 k,表示要划分成的循环排列的数量,第二类斯特林数 S(n, k) 表示将这 n 个物体划分成 k 个非空循环排列的方法数。 第二类斯特林数满足以下递推关系: S...

    组合数学中的第二类斯特林数“同一列”的C++代码实现

    给定一个正整数 n,表示要划分的物体的数量,以及一个正整数 k,表示要划分成的循环排列的数量,第二类斯特林数 S(n, k) 表示将这 n 个物体划分成 k 个非空循环排列的方法数。 第二类斯特林数满足以下递推关系: S...

    算法竞赛中的第一类斯特林数“同一行”的C++代码实现

    给定一个正整数n,表示要划分的物体的数量,以及一个正整数k,表示要划分成的循环排列的数量,第一类斯特林数 {n \atop k}(有时也写作c(n, k)或Stirling(n, k))表示将这n个物体划分成k个循环排列的方法数。...

    C语言学习实例220例

    119 超长正整数的加法 第四部分 图形篇 120 绘制直线 121 绘制圆 122 绘制圆弧 123 绘制椭圆 124 设置背景色和前景色 125 设置线条类型 126 设置填充类型和填充颜色 127 图形文本的输出 128 金刚石图案 129 飘带图案...

    200个经典C程序源码小游戏

    119 超长正整数的加法 第四部分 图形篇 120 绘制直线 121 绘制圆 122 绘制圆弧 123 绘制椭圆 124 设置背景色和前景色 125 设置线条类型 126 设置填充类型和填充颜色 127 图形文本的输出 ...

    算法分析与设计习题集答案

    20、 键盘输入一个高精度的正整数N(此整数中没有‘0’),去掉其中任意S个数字后剩下的数字按原左右次序将组成一个新的正整数。编程对给定的N和S,寻找一种方案使得剩下的数字组成的新数最小(输出应包括所去掉的...

    关于排序算法的c ++程序

    输入:input.txt,第一行是元素数目N(1-30),后面是N个整数,例如: 5 7 -2 -1 0 6 输出:如果输入合法,输出重整之后的列表,每个整数间用一个空格间隔,最后一个元素之后不能有空格;否则输出“WRONG”。最后...

    C语言经典例题100道

    29.求解正整数位数 30.判断回文数 31.星期几猜测游戏 32.改变文本颜色 33.学习gotoxy()与clrscr()函数 34.练习函数调用 35.设置文本颜色 36.求100之内的素数 37.对10个数进行排序 38.求3*3矩阵对角线元素之和 39....

    C C++算法实例.c

    (1) n个活动每个活动有一个开始时间和一个结束时间,任一时刻仅一项活动进行,求满足活动数最多的情况。 解:按每项活动的结束时间进行排序,排在前面的优先满足。 (2)会议室空闲时间最少。 (3)每个客户有...

    C语言实例解析精粹

    119 超长正整数的加法 第四部分 图形篇 120 绘制直线 121 绘制圆 122 绘制圆弧 123 绘制椭圆 124 设置背景色和前景色 125 设置线条类型 126 设置填充类型和填充颜色 127 图形文本的输出 128 金刚石图案 ...

    数据结构课程设计

    一开始任选一个正整数作为报数的上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止。报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一人开始重新从1报数,如此下去,直到所有人全部...

    220个经典C程序源码文件,可以做为你的学习设计参考.zip

    119 超长正整数的加法 第四部分 图形篇 120 绘制直线 121 绘制圆 122 绘制圆弧 123 绘制椭圆 124 设置背景色和前景色 125 设置线条类型 126 设置填充类型和填充颜色 127 图形文本的输出 128 金刚石图案 ...

    200个经典C程序【源码】

    119 超长正整数的加法 第四部分 图形篇 120 绘制直线 121 绘制圆 122 绘制圆弧 123 绘制椭圆 124 设置背景色和前景色 125 设置线条类型 126 设置填充类型和填充颜色 127 图形文本的输出 128 金刚石图案 ...

    220个C语言程序源代码.zip

    119 超长正整数的加法 第四部分 图形篇 120 绘制直线 121 绘制圆 122 绘制圆弧 123 绘制椭圆 124 设置背景色和前景色 125 设置线条类型 126 设置填充类型和填充颜色 127 图形文本的输出 128 金刚石图案 ...

    200个经典C程序源码(包括基础篇+数据结构篇+数值计算与趣味数学篇+图形篇+系统篇+常见试题解答篇).zip

    119 超长正整数的加法 第四部分 图形篇 120 绘制直线 121 绘制圆 122 绘制圆弧 123 绘制椭圆 124 设置背景色和前景色 125 设置线条类型 126 设置填充类型和填充颜色 127 图形文本的输出 128 金刚石图案 ...

    200个C程序.rar

    119 超长正整数的加法 第四部分 图形篇 120 绘制直线 121 绘制圆 122 绘制圆弧 123 绘制椭圆 124 设置背景色和前景色 125 设置线条类型 126 设置填充类型和填充颜色 127 图形文本的输出 128 金刚石图案 ...

    220个C语言程序源代码集合.zip

    119 超长正整数的加法 第四部分 图形篇 120 绘制直线 121 绘制圆 122 绘制圆弧 123 绘制椭圆 124 设置背景色和前景色 125 设置线条类型 126 设置填充类型和填充颜色 127 图形文本的输出 128 金刚石图案 ...

    《数据结构 1800题》

    其中 n为正整数,则最后一行的语句频度在最坏情况下是(D ) 郴州都市网 www.0735.cc郴州人才网 www.CZHR.com www.989.org 《数据结构 1800题》 A. O(n) B. O(nlogn) C. O(n3) D. O(n2) 【南京理工大学 ...

Global site tag (gtag.js) - Google Analytics