把整数1-9填入算式 ABCD/EFGHI中,每个数字只能用1次,且EFGHI是ABCD的2倍(整除)。输出所有可能的情况。这是很久以前我做过的一道题,当时的算法并不好,至少是O(N^2)。现在看看有没有更好的解法,请大家一起探讨。
解决方案 »
- 求 单纯形法 的java实现。。。求源码,急。。。
- 用swing做的表格打印预览的代码
- 使用ArrayList动态构造二维数组
- validator验证问题,十分急,分不够立刻加!!!!
- 请求推荐五子连珠的Java代码
- JPanel上的addKeyListener方法没有起作用,为什么?
- 这段代码运行有错误,帮忙看看行吗?
- 高分求救,SimpleDateFormat.parse()方法出错?
- 我做了一个jtree,可以增加和删除节点。现在我想在增加新节点后,当前界面上选择的节点就变为新的节点,删除节点后,当前选择的节点就变为
- 能不能在java程序运行的时候产生odbc数据源?
- 关于单选按钮的问题
- Java JTextField提示空指针异常
E的取值是多少,我看只能是1吧? 好像 2 + 都不行。否则EFGHI的一半一定是个五位数了。
I的取值呢?因为2倍的关系,I的取值只能是偶数。那么E的取值是1了,那么A的取值基本也固定了基本是5了
5BCD 1FGH(偶数)2 4 6 8中取 C41为I,然后剩下的就是P66。简单组合计算一下,量大概是1000次之内的计算。
这只是第1问,下面要求出EFGHI是ABCD的k[2,9]倍(整除)的情况,不会每次都这么分析把。
e = 1 #
arr = [2, 3, 4, 6, 7, 8, 9]for item in arr.permutation(7)
b, c, d, f, g, h, i = *item
if i % 2 == 0
m = 10000 + f * 1000 + g *100 + h * 10 + i
n = 5000 + b * 100 + c * 10 + d
if m / n * 2 == m
p item
end
end
end我哪里出错了? 看了一会儿。。没看出来k[2, 9]是什么意思?
[2, 3, 9, 4, 6, 7, 5, 8]
[2, 9, 4, 3, 7, 6, 5, 8]
[3, 9, 4, 2, 5, 7, 6, 8]
[4, 3, 9, 2, 7, 5, 6, 8]
[5, 8, 3, 2, 7, 4, 9, 6]
[6, 7, 2, 9, 3, 4, 5, 8]
[6, 7, 9, 2, 3, 5, 8, 4]
[6, 9, 2, 7, 3, 8, 5, 4]
[7, 2, 6, 9, 4, 5, 3, 8]
[7, 2, 9, 3, 4, 5, 8, 6]
[7, 3, 2, 9, 4, 6, 5, 8]
[7, 6, 9, 2, 5, 3, 8, 4]
[7, 9, 2, 3, 5, 8, 4, 6]
[7, 9, 3, 2, 5, 8, 6, 4]
[9, 2, 6, 7, 8, 5, 3, 4]
[9, 2, 7, 3, 8, 5, 4, 6]
[9, 3, 2, 7, 8, 6, 5, 4]
对应的是 abcd fghi
Output completed (0 sec consumed) - Normal Termination
就是说要输出 ABCD/EFGHI = 1/2 ,ABCD/EFGHI = 1/3 ...... ABCD/EFGHI = 1/9等8种情况的结果
刚才写了下,ABCD/EFGHI = 1/2有12种结果
6729 13458 k = 2
6792 13584 k = 2
6927 13854 k = 2
7269 14538 k = 2
7293 14586 k = 2
7329 14658 k = 2
7692 15384 k = 2
7923 15846 k = 2
7932 15864 k = 2
9267 18534 k = 2
9273 18546 k = 2
9327 18654 k = 2
count = 12
核心思想是对于所有可能的ABCD,乘以倍数后检验是否ABCDEFGHI刚好出现了1~9
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;public class trick1 { // 参数: n ---- EFGHI = n * ABCD
// 返回: 含ABCD的List
public static List<Integer> find(int n) {
List<Integer> list = new ArrayList<Integer>();
int i,j,k,l;
int x;
for (i=1; i<=9; i++) {
for (j=1; j<=9; j++) {
if (j==i) continue;
for (k=1; k<=9; k++) {
if (k==i||k==j) continue;
for (l=1; l<=9; l++) {
if (l==i||l==j||l==k) continue;
x = i*1000+j*100+k*10+l;
if (validate(x,n)) list.add(x);
}
}
}
}
return list;
}
public static boolean validate(int x, int n) {
int x2 = x*n, mod;
if (x2<10000 || x2>99999) return false;
String s = ""+x+x2;
if (s.indexOf("0")>=0) return false;
HashMap map = new HashMap();
for (int i=0; i<s.length(); i++)
map.put(s.charAt(i), null);
return map.size()==s.length();
} //测试 (2倍,3倍)
public static void main(String[] args) {
int n;
List<Integer> result;
n = 2;
System.out.println("n=" + n);
result = find(n);
for (int i=0; i<result.size(); i++)
System.out.println(result.get(i) + " " + result.get(i)*n);
System.out.println(); n = 3;
System.out.println("n=" + n);
result = find(n);
for (int i=0; i<result.size(); i++)
System.out.println(result.get(i) + " " + result.get(i)*n);
System.out.println();
}}
1~n个数 填入 X1,X2,...Xn, 给定m, 令 Xm+1...Xn刚好是X1X2...Xm的整数倍不然读者很难知道你的意图到底是需要哪些参数可变
排列组合的速度其实是很快的,因为有固定的算法。
而for的,要解决是不是重复的问题。
不管用什么算法排列,都要解决重复问题吧,只是api帮你实现了还是自己实现的区别,执行效率应该是一个数量级
int k = 2; //[2, 9]
String s1, s2;
int i, j, t;
boolean dup;
for (i=1234; i<100000/k; i++) {
s1 = String.valueOf(i);
j = i;
dup = false;
while (j > 0) {
if (s1.length()-s1.replaceAll(""+(j%10), "").length() > 1) {
dup = true;
break;
}
j /= 10;
}
if (dup) {continue;}
j = i * k;
s2 = String.valueOf(k);
t = j;
dup = false;
while (t > 0) {
if (s2.length()-s2.replaceAll(""+(t%10), "").length() > 1 ||
s1.contains(""+(t%10))) {
dup = true;
break;
}
t /= 10;
}
if (dup) {continue;}
System.out.printf("%d/%d,k=%d\n", i, j, k);
}
}
这种题目标准写法都是for的,我用Ruby有讨巧的地方。我小时学GWBasic的时候都这么干。
看这个C++代码,得到一个排练除了交换两个数字,就是一次递归,都谈不到时间和空间复杂度的问题。
恩,是写的很好。
这题如果要追求代码简洁,我也可以这样写:
for (int i=1234; i<9876; i++) {
if (dup(i)) continue;
}
只是在楼主指定了长度为4之后,我觉得用4个for代码的复杂性还可接受,而执行效率要比上述简洁代码高。因为很多重复的在外层的for就被拦截了,不需要真的逐个比较。
现在不是要研究最好的算法么,当然是执行效率优先了
话说回来,我倒是真的很好奇O(N^2)的算法。目前大家写的,都是接近O(N^4)的
alexandertech 平均用时差不多0.08-0.09s,答案是对的,应该可以再优化下
(阿宝) 平均用了差不多1s,而且还错了。结果里没有0我的代码平均用时差不多0.02-0.03s,感觉写的还不够好,先贴上了看看,别用板砖砸就行了。import java.util.ArrayList;/*
* 把整数1-9填入算式 ABCD/EFGHI中,每个数字只能用1次,且EFGHI是ABCD的k[2,9]倍(整除)。输出所有可能的情况。
*/public class Test {
static int[] num = new int[9];
static int count = 0;
/**
* @param args null
*/
public static void main(String[] args) {
double start = System.nanoTime();
for(int i = 2;i <= 9;i++)
getResult(i);
System.out.println("count = " + count);
double end = System.nanoTime();
System.out.println("time = " + (end - start) / 1e9 + "秒");
}
/**
* @param k [2,9]
*/
static void getResult(int k){
for(int i = 12345 / k;i <= 49876;i++){
if(i * k <= 98765 && i * k >= 12345 && check(i,i * k) == true){
System.out.println(i + " " + i * k + " k = " + k);
count++;
}
}
} static boolean check(int a,int b){
int[] num = new int[9];
while(a != 0 || b != 0){
if(b % 10 != 0 && num[b % 10 - 1] == 0)
num[b % 10 - 1] = 1;
else
return false;
b /= 10;
if(a == 0)
continue;
if(a % 10 != 0 && num[a % 10 - 1] == 0)
num[a % 10 - 1] = 1;
else
return false;
a /= 10;
}
return true;
}
}time = 0.025207856秒
12345/k很巧妙,<=49876应该有问题,为什么不是<=9876呢,这样会更快2)比较速度,是不能用毫秒比的,起码在秒级别上比,象这样:
for (int j=0; j<1000; j++)
for(int i = 2;i <= 9;i++)
getResult(i);
跑1000次,比较时间才有意义。毫秒级别的跑1次误差太大
在我的机器上,跑1000次,你的程序是25.09秒,我的是19.85秒。
把你上边的49876改为9876,你的程序是9.71秒3) 为什么说这个算法是O(N^2)呢?这里N是什么?
如果核心算法用我的,check算法用你的,结果会更快,跑1000次4.1秒。
因为核心算法中,我拿到的是排列,比你遍历12345/K~9876更有效率
校验算法中,你用int[],比我用HashMap节省了创建对象的时间
import java.util.ArrayList;
//import java.util.HashMap;
import java.util.List;public class trick1 {
static int count=0; // 参数: n ---- EFGHI = n * ABCD
// 返回: 含ABCD的List
public static List<Integer> find(int n) {
List<Integer> list = new ArrayList<Integer>();
int i,j,k,l;
int x;
for (i=1; i<=9; i++) {
for (j=1; j<=9; j++) {
if (j==i) continue;
for (k=1; k<=9; k++) {
if (k==i||k==j) continue;
for (l=1; l<=9; l++) {
if (l==i||l==j||l==k) continue;
x = i*1000+j*100+k*10+l;
if (check(x,x*n))
// if (validate(x,n))
list.add(x);
}
}
}
}
return list;
}
/*
public static boolean validate(int x, int n) {
int x2 = x*n, mod;
if (x2<10000 || x2>99999) return false;
String s = ""+x+x2;
if (s.indexOf("0")>=0) return false;
HashMap map = new HashMap();
for (int i=0; i<s.length(); i++)
map.put(s.charAt(i), null);
return map.size()==s.length();
}*/ static boolean check(int a,int b){
int[] num = new int[9];
int c=0;
while(a != 0 || b != 0){
if(b % 10 != 0 && num[b % 10 - 1] == 0) {
num[b % 10 - 1] = 1;
c++;
}
else
return false;
b /= 10;
if(a == 0)
continue;
if(a % 10 != 0 && num[a % 10 - 1] == 0) {
num[a % 10 - 1] = 1;
c++;
}
else
return false;
a /= 10;
}
return c==9;
//return true;
}
public static void main(String[] args) {
int n;
List<Integer> result; double start = System.nanoTime();
for (int j = 0; j < 1000; j++)
for (int i = 2; i <= 9; i++) {
result = find(i);
count += result.size();
}
System.out.println("count = " + count);
double end = System.nanoTime();
System.out.println("time = " + (end - start) / 1e9 + "秒");
/*
n = 2;
System.out.println("n=" + n);
result = find(n);
for (int i=0; i<result.size(); i++)
System.out.println(result.get(i) + " " + result.get(i)*n);
System.out.println(); n = 3;
System.out.println("n=" + n);
result = find(n);
for (int i=0; i<result.size(); i++)
System.out.println(result.get(i) + " " + result.get(i)*n);
System.out.println();
*/
}}
将你的全排列算法改进了一下,在我机器上跑1000次能进1s.
public class trick1 {
static int count = 0; // 参数: n ---- EFGHI = n * ABCD
// 返回: 含ABCD的List
public static void find(int n) {
int i, j, k, l;
int x;
for (i = 12 / n; i <= 9; i++) {// 把 1 改成 12 / n
for (j = 1; j <= 9; j++) {
if (j == i)
continue;
for (k = 1; k <= 9; k++) {
if (k == i || k == j)
continue;
for (l = 1; l <= 9; l++) {
if (l == i || l == j || l == k)
continue;
x = i * 1000 + j * 100 + k * 10 + l;
if(x * n < 12345)//不加判断会多解
continue;
if (check(x, x * n)){
count++;
}
}
}
}
}
} //去掉了变量,上面已经判断
static boolean check(int a, int b) {
int[] num = new int[9];
while (a != 0 || b != 0) {
if (b % 10 != 0 && num[b % 10 - 1] == 0) {
num[b % 10 - 1] = 1;
} else
return false;
b /= 10;
if (a == 0)
continue;
if (a % 10 != 0 && num[a % 10 - 1] == 0) {
num[a % 10 - 1] = 1;
} else
return false;
a /= 10; }
return true;
} public static void main(String[] args) {
double start = System.nanoTime();
for (int j = 0; j < 1000; j++)
for (int i = 2; i <= 9; i++) {
find(i);
}
System.out.println("count = " + count);
double end = System.nanoTime();
System.out.println("time = " + (end - start) / 1e9 + "秒");
}
}