锁定老帖子 主题:对于这个题目,看看大家有什么效率更高的算法
精华帖 (0) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-10-19
最后修改:2010-10-19
下午写了这个算法。跑了下 n=23时, 打印全部结果到控制台花了14秒时间,内存一直在8兆左右。
晚上回家又试着跑了 n=30,把结果输出到文件中,花了554秒,内存变成9兆(可能跟我把BufferedWriter的buffer size 提高到16k有关)。输出的结果文件有2g大。。。 package method; import java.io.BufferedWriter; import java.io.CharArrayWriter; import java.io.IOException; import java.io.OutputStreamWriter; public class Fibonacci { private int n = 0; private long f0 = 1; private long f1 = 1; private long f2 = 2; private long[] queue = null; public Fibonacci(int n) { if(n < 0) { throw new IllegalArgumentException("n can not be negative."); } this.n = n; queue = new long[n+1]; caculate(); } private void caculate(){ // n = 0, 1, 2 switch(n){ case 2: queue[2] = f2; case 1: queue[1] = f1; case 0: queue[0] = f0; return; default: break; } // n > 2 queue[0] = f0; queue[1] = f1; queue[2] = f2; for (int i = 3; i <= n; i++) { queue[i] = queue[i - 1] + queue[i - 2] + queue[i -3]; System.out.println("Fibonacci("+i+")=" + queue[i]); } } public long[] getFibonacciQueue() { return queue; } public long f(int i) { if(i < 0) { //throw new IllegalArgumentException("i can not be negative."); return 0; } if(i > n) { throw new IllegalArgumentException("i can not be bigger than n."); } return queue[i]; } public void printDetail() throws IOException { CharArrayWriter caw = new CharArrayWriter(2 * n + 2); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out), 4096); for(long y = 0; y < f(n); y++) { for(int x = 0; x < n; x++) { char stepnum = getStepNum(x, y); if(stepnum == 0) { continue; }else { if(caw.size() > 0) { caw.write(','); } caw.write(stepnum); } } caw.write("\r\n"); caw.writeTo(out); caw.reset(); } out.flush(); } private char getStepNum(int x, long y) { if(x == 2 && y == 6) { System.out.println(""); } int k = 0; int i = 0; for (; i < x; i++) { if(y >= f(n - k - 1) + f(n - k - 2)) { if(n > k + 3) { y -= f(n - k - 1) + f(n - k - 2); k += 3; }else { break; } }else if (y >= f(n - k - 1)) { if(n > k + 2) { y -= f(n - k - 1); k += 2; }else { break; } }else { if(n > k + 1) { k += 1; }else { break; } } } if(y < f(n - k - 1)) { if(n <= k + 1 && i < x) { return 0; } return '1'; }else if (y < f(n - k - 1) + f(n - k - 2)) { if(n <= k + 2 && i < x) { return 0; } return '2'; }else { if(n <= k + 3 && i < x) { return 0; } return '3'; } } public static void main(String[] args) throws IOException { long start = System.currentTimeMillis(); int n = 23; Fibonacci fib = new Fibonacci(n); System.out.println("[Result]Fibonacci("+n+")=" + fib.f(n)); fib.printDetail(); System.out.println("Cost:" + (System.currentTimeMillis() - start) + "ms"); } } |
|
返回顶楼 | |
发表时间:2010-10-19
shkailiao 写道 yiyidog125 写道 试试我这个 可能也没变好 这题我从面试出题者的角度考虑应该只算不同走法就好了 不应该打印路径
public class StairsWeak { /** * @param args */ public static void main(String[] args) { List<List<WeakReference<Integer>>> list = steps(20); for (List<WeakReference<Integer>> i : list) { System.out.print("["); for (WeakReference<Integer> j : i) { System.out.print(j.get() + " "); } System.out.println("]"); } } private static List<List<WeakReference<Integer>>> steps(int n) { //only 1 stair List<List<WeakReference<Integer>>> secLast = new ArrayList<List<WeakReference<Integer>>>(); List<WeakReference<Integer>> tmp = new ArrayList<WeakReference<Integer>>(); tmp.add(new WeakReference<Integer>(1)); secLast.add(tmp); //2 stairs List<List<WeakReference<Integer>>> last = new ArrayList<List<WeakReference<Integer>>>(); tmp = new ArrayList<WeakReference<Integer>>(); tmp.add(new WeakReference<Integer>(1)); tmp.add(new WeakReference<Integer>(1)); last.add(tmp); tmp = new ArrayList<WeakReference<Integer>>(); tmp.add(new WeakReference<Integer>(2)); last.add(tmp); //3 stairs List<List<WeakReference<Integer>>> curr = new ArrayList<List<WeakReference<Integer>>>(); tmp = new ArrayList<WeakReference<Integer>>(); tmp.add(new WeakReference<Integer>(1)); tmp.add(new WeakReference<Integer>(1)); tmp.add(new WeakReference<Integer>(1)); curr.add(tmp); tmp = new ArrayList<WeakReference<Integer>>(); tmp.add(new WeakReference<Integer>(2)); tmp.add(new WeakReference<Integer>(1)); curr.add(tmp); tmp = new ArrayList<WeakReference<Integer>>(); tmp.add(new WeakReference<Integer>(1)); tmp.add(new WeakReference<Integer>(2)); curr.add(tmp); tmp = new ArrayList<WeakReference<Integer>>(); tmp.add(new WeakReference<Integer>(3)); curr.add(tmp); if (n == 1) { return secLast; } else if (n == 2) { return last; } else if (n == 3) { return curr; } else { int count = 3; while (count != n) { System.gc(); List<List<WeakReference<Integer>>> nList = new ArrayList<List<WeakReference<Integer>>>(); for (List<WeakReference<Integer>> list : secLast) { tmp = new ArrayList<WeakReference<Integer>>(); tmp.addAll(list); tmp.add(new WeakReference<Integer>(3)); nList.add(tmp); } for (List<WeakReference<Integer>> list : last) { tmp = new ArrayList<WeakReference<Integer>>(); tmp.addAll(list); tmp.add(new WeakReference<Integer>(2)); nList.add(tmp); } for (List<WeakReference<Integer>> list : curr) { tmp = new ArrayList<WeakReference<Integer>>(); tmp.addAll(list); tmp.add(new WeakReference<Integer>(1)); nList.add(tmp); } secLast = last; last = curr; curr = nList; count++; } } return curr; } } 很抱歉的说,题目是明确说要打印路径的。 那你跑这个有没觉得内存耗的好点了? |
|
返回顶楼 | |
发表时间:2010-10-20
|
|
返回顶楼 | |
发表时间:2010-10-20
|
|
返回顶楼 | |
发表时间:2010-10-20
唉,郁闷啊,看了之后,竟然一点思路都没有,谁给点
|
|
返回顶楼 | |
发表时间:2010-10-25
LZ可以看一下这篇文档,相信会受益匪浅的 小问题大学问呐 |
|
返回顶楼 | |
发表时间:2010-11-01
night_stalker 写道
不错的算法 我写了个java版 public static void main(String[] args) throws IOException { long start = System.currentTimeMillis(); out_step(35); long end = System.currentTimeMillis(); System.out.println(end-start); /*FileInputStream in = new FileInputStream("g:/data.txt"); System.out.println(in.read()); in.close();*/ } public static void count(Writer writer,StringBuffer s ,int i,int j,int k) throws IOException{ if(i==0&&j==0&&k==0){ writer.append(s+"\n"); return; } if(i>0){ count(writer,new StringBuffer(s).append("1"),i-1,j,k); } if(j>0){ count(writer,new StringBuffer(s).append("2"),i,j-1,k); } if(k>0){ count(writer,new StringBuffer(s).append("3"),i,j,k-1); } } public static void out_step(int n) throws FileNotFoundException{ BufferedWriter out = null; try { out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("g:/data.txt")),1024*1024); for(int i=0;i<=n/3;i++){ int m = n-3*i; for(int j=0;j<=m/2;j++){ count(out, new StringBuffer(), (m-2*j),j, i); } } } catch (IOException e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } 内存使用一直在6m以下,关键是看硬盘有多大了。。。 测了一下35个台阶,用时2270171ms 半个多小时,生成文件有25g。汗。。。幸亏我硬盘够大 |
|
返回顶楼 | |
发表时间:2010-11-02
lovemylover 写道 恩,差不多吧,我没怎么看你的解法,说句实话太多太乱了。排除递归之外,我实在没有想出更好的解法。线性规划的有些解法实现起来太复杂,就没有去尝试了,所以也不知道那种解法的时间复杂度怎么样
f(x) = f(x-1) + f(x-2) + f(x-3) 是吧,3*3的矩阵,如果求第x项,时间复杂度 O(3log(x)),矩阵乘法要用快速幂 |
|
返回顶楼 | |
发表时间:2010-11-26
最后修改:2010-11-26
这个问题可以用非递归算法来做。比较了一下,性能比递归算法快很多。具体请看
http://yeaya.iteye.com/admin/blogs/824792 |
|
返回顶楼 | |
发表时间:2010-11-27
递归吃内存是误解,递归算法的限制在于堆栈深度, 由于要计算出所有结果,所以台阶数不可能太长,递归算法是没有问题的。关键是怎样存储结果。下面的算法是用4进制数表示结果,java里的long值最多可以表达32为4进制数,所以下面算法理论上最多只能计算32级台阶。
31级台阶的计算结果:
n=31
count=98950096 used time 3797 ms. memory used 794MB 下面是源代码
import java.util.ArrayList; public class Test { static class LongArray { static final int BLOCK_SIZE = 1000000; final ArrayList<long[]> list = new ArrayList<long[]>(); long[] current = new long[BLOCK_SIZE]; int index = 0; int total = 0; void add(long val) { if(index>=BLOCK_SIZE) { list.add(current); current = new long[BLOCK_SIZE]; index = 0; } current[index++] = val; total++; } int size() { return total; } long get(int idx) { int i = idx/BLOCK_SIZE; idx %= BLOCK_SIZE; if(i<list.size()) return list.get(i)[idx]; return current[idx]; } } static void calc(LongArray list,long val,int steps,int n) { val<<=2; for(int i=0;i<3;i++) { val++; steps++; if(steps == n) { list.add(val); break; } calc(list,val,steps,n); } } static LongArray calc(int n) { LongArray ar = new LongArray(); calc(ar,0,0,n); return ar; } public static void main(String[] args) { int n = 31; //需要1G JVM内存 long start = System.currentTimeMillis(); LongArray list = calc(n); long end = System.currentTimeMillis(); System.out.println("n=" + n); System.out.println("count=" + list.size()); System.out.println("used time " + (end-start) + " ms."); System.out.println("memory used " + ((Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory())/1000000L) + "MB"); /* for(int i=0;i<list.size();i++) { System.out.println(Long.toString(list.get(i),4)); }*/ } }
|
|
返回顶楼 | |