使用三种方法求解前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的数据与获取到的索引对应的数据位置替换,这样就可以达到全排列的目的。
使用三种方法求解前N个正整数的排列的更多相关文章
- 三种方法求解最大子区间和:DP、前缀和、分治
题目 洛谷:P1115 最大子段和 LeetCode:最大子序和 给出一个长度为 \(n\) 的序列 \(a\),选出其中连续且非空的一段使得这段和最大. 挺经典的一道题目,下面分别介绍 \(O(n) ...
- 数组k平移三种方法(java)
上代码,本文用了三种方法实现,时间复杂度不一样,空间复杂度都是o(1): public class ArrayKMove { /** * 问题:数组的向左k平移,k小于数组长度 * @param ar ...
- 【SQL】Oracle分页查询的三种方法
[SQL]Oracle分页查询的三种方法 采用伪列 rownum 查询前10条记录 ? 1 2 3 4 5 6 7 8 9 10 11 [sql] select * from t_user t whe ...
- Java中获取键盘输入值的三种方法
Java中获取键盘输入值的三种方法 Java程序开发过程中,需要从键盘获取输入值是常有的事,但Java它偏偏就没有像c语言给我们提供的scanf(),C++给我们提供的cin()获取键盘输入值 ...
- 【Cocos2d-x游戏开发】解决Cocos2d-x中文乱码的三种方法
众所周知,Cocos2d-x是一款不错的开源引擎,但是在Cocos2d-x中直接使用中文是无法正确显示的.比如下面的情况: 解决这个问题常用的有三种方法:1.通过转换为UTF-8编码来显示.2.使用i ...
- Eclipse插件安装的三种方法
转自:http://www.blogjava.net/tangzurui/archive/2008/06/30/211669.html 整理了一下格式. (前两种安装方式以多国语言包的安装为例) 1 ...
- Centos内核升级的三种方法
本文出自 “存储之厨” 博客,请务必保留此出处http://xiamachao.blog.51cto.com/10580956/1755354 在基于CentOS平台的工作过程中,难免有时需要升级或者 ...
- Struts2获取request三种方法
Struts2获取request三种方法 struts2里面有三种方法可以获取request,最好使用ServletRequestAware接口通过IOC机制注入Request对象. 在Actio ...
- MyEclipse6.5安装SVN插件的三种方法
MyEclipse6.5安装SVN插件的三种方法 方法一.如果可以上网可在线安装 1. 打开Myeclipse,在菜单栏中选择Help→Software Updates→Find and Instal ...
随机推荐
- flask开发没有解决的bug记录
sqlalchemy.exc.InvalidRequestError sqlalchemy.exc.InvalidRequestError: This Session's transaction ha ...
- WindowsServer2012 搭建域错误“本地Administraor账户不需要密码”
标签:MSSQL/SQLServer/域控制器提升的先决条件验证失败/密码不符合要求 概述 在安装WindowsServer2012域控出现administrator账户密码不符合要求的错误,但是实际 ...
- 关于git的一些理论知识
一.什么是版本控制器 好多刚用git的coder一说起git,就随口会说出版本控制器嘛,我问那是干嘛的,大部分人就回答上传代码的.然后会用,但是有些理论你问他们他们就不知道了,比如不是代码的文件就不能 ...
- 记vue API 知识点
1. v-cloak指令:这个指令保持在元素上直到关联实例结束编译.和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标 ...
- ECMAScript中的两种属性
数据属性 数据属性包含一个数据值的位置.在这个位置可以读取和写入值.数据属性一般用于存储数据数值. 数据属性有4个描述其行为的特征. configurable:true/false,是否可以通过del ...
- Python:监控ASM剩余空间
#!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'Jipu FANG' version = 0.1 import cx_Oracle ...
- [数据清洗]- Pandas 清洗“脏”数据(三)
预览数据 这次我们使用 Artworks.csv ,我们选取 100 行数据来完成本次内容.具体步骤: 导入 Pandas 读取 csv 数据到 DataFrame(要确保数据已经下载到指定路径) D ...
- 总结oninput、onchange与onpropertychange事件的用法和区别
前端页面开发的很多情况下都需要实时监听文本框输入,比如腾讯微博编写140字的微博时输入框hu9i动态显示还可以输入的字数.过去一般都使用onchange/onkeyup/onkeypress/onke ...
- vim 高级应用
1 全文内容删除 方法1: 按ggdG方法2: :%d
- Benchmark Test On Android Devices
一.Android设备上的Benckmark测试概述 同PC相比,在Android设备上的性能测试还没有一个公认的标准.也没有PC上那么多的测试程序集.但我们可以通过一些工具所得到的信息更好的了解设备 ...