多重循环优化
2016-03-30 11:41
218 查看
四平方和 (程序设计)
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。
比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:
0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法
程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开
例如,输入:
5
则程序应该输出:
0 0 1 2
再例如,输入:
12
则程序应该输出:
0 2 2 2
再例如,输入:
773535
则程序应该输出:
1 1 267 838
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 3000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
这道题,我当时就是写了一个四重循环遍历搜索,也跑了最大的一组样例,没有超时,就直接交了!后来,在网上发现,这样做好像是超时的。唉,还是自己做题做的少,算法研究的少啊!要是想在任何一门比赛中得到好成绩,还是需要算法过硬才行啊!
上面这个代码,虽然我试了几次都没有超时,最大的耗时是2800ms,可是毕竟是4重循环,虽然实际为O(n^2),但是参考了书上的代码进行如下优化:
优化后的算法复杂度从O(n^4)变为O(n^3*log n),原理是这样的,既然是求 a^2 + b^2 + c^2 + d^2 = N,先枚举出[0,sqrt(N)+10](加上10是为了保险)所有值的平方,并将其存在arr数组中(arr[i] = i * i),然后问题就变成了“在数组arr中是否存有四个数A,B,C,D使得A+B+C+D=N”,将等式变形D=N-A-B-C,就是等价于在数组arr中寻找有没有t=N-A-B-C这样一个值,由于数组arr是升序的,可以直接使用二分查找,其复杂度为log n,再加上外围的三层循环,总复杂度为O(n^3*log n)。
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。
比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:
0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法
程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开
例如,输入:
5
则程序应该输出:
0 0 1 2
再例如,输入:
12
则程序应该输出:
0 2 2 2
再例如,输入:
773535
则程序应该输出:
1 1 267 838
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 3000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
这道题,我当时就是写了一个四重循环遍历搜索,也跑了最大的一组样例,没有超时,就直接交了!后来,在网上发现,这样做好像是超时的。唉,还是自己做题做的少,算法研究的少啊!要是想在任何一门比赛中得到好成绩,还是需要算法过硬才行啊!
//1.四重循环直撸 import java.util.Scanner; public class Main { public static int N = 0; public static void Op(){ for(int a=0;a*a<N;a++){ for(int b=0;b*b<N;b++){ for(int c=0;c*c<N;c++){ for(int d=0;d*d<N;d++){ if(a*a+b*b+c*c+d*d==N){ System.out.println(a+" "+b+" "+c+" "+d); return ; } } } } } } public static void main(String[] args) { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); while(in.hasNext()){ N = in.nextInt(); //long t1 = System.currentTimeMillis(); Op(); //long t2 = System.currentTimeMillis(); //System.out.println("Time cost:"+(t2-t1)); } } }
上面这个代码,虽然我试了几次都没有超时,最大的耗时是2800ms,可是毕竟是4重循环,虽然实际为O(n^2),但是参考了书上的代码进行如下优化:
//枚举+二分搜索优化 import java.util.Arrays; import java.util.Random; import java.util.Scanner; public class Main { public static int n, line; public static int[] arr; public static void find(){ arr = new int[line]; for(int i=0;i<line;i++) arr[i] = i * i; for(int a=0;a<line;a++){ for(int b=0;b<line;b++){ for(int c=0;c<line;c++){ int t = n - arr[a] - arr[b] - arr[c]; int index = -1; index = Arrays.binarySearch(arr, t); if(index>=0){ // System.out.println("n:"+n); System.out.println(a+" "+b+" "+c+" "+(int)Math.sqrt(t)); return ; } } } } } public static void main(String[] args) { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); // Random rand = new Random(); for(int i=0;i<10000;i++){ //n = rand.nextInt(5000000); n = in.nextInt(); long t1 = System.currentTimeMillis(); line = (int)Math.sqrt(n)+10; find(); long t2 = System.currentTimeMillis(); // System.out.println("Time cost:"+(t2-t1)); // if(t2-t1>3000){ // System.out.println("breakpoint!"); // break; // } } } }
优化后的算法复杂度从O(n^4)变为O(n^3*log n),原理是这样的,既然是求 a^2 + b^2 + c^2 + d^2 = N,先枚举出[0,sqrt(N)+10](加上10是为了保险)所有值的平方,并将其存在arr数组中(arr[i] = i * i),然后问题就变成了“在数组arr中是否存有四个数A,B,C,D使得A+B+C+D=N”,将等式变形D=N-A-B-C,就是等价于在数组arr中寻找有没有t=N-A-B-C这样一个值,由于数组arr是升序的,可以直接使用二分查找,其复杂度为log n,再加上外围的三层循环,总复杂度为O(n^3*log n)。
相关文章推荐
- 柳峰微信公众平台开发教程企业号修改篇(AccessToken篇)
- git使用教程——Mob分享总结
- MySQL 常用的命令
- DataBinding 再也不用写findviewbyId了
- Service--简单学习
- 35 个 jQuery 小技巧
- Camel——涨知识了,骆驼命名法
- IOS开发-UI学习-沙盒机制&文件操作
- iOS开发常用的资源和资料
- TableView Cell
- Android用户注册界面
- PHP中的函数-- foreach()的用法详解
- simpleCursorAdapter中的listview获取内容
- Tomcat ( 单机多 Tomcat 并存 )
- extjs控制器调用其他视图的函数实现控件赋值。
- HTML的各个标签的默认样式有哪些
- dubbo简述
- freemarker教程
- androird 优秀新闻github
- ApplePay调研