不能得到40或50的斐波纳契内存不足

时间:2017-07-17 04:34:37

标签: java

我在求职面试中遇到了以下问题,但直到最后都无法解决:

你有字符串" kake"和字符串" echo"

你有函数create(int n)并返回以下内容:

if n equals 0

    output “kake”

if n equals 1

   output “echo”

if n greater than 1

   output create(n-1) concatenated with create(n-2)

然后在另一个采用n和子串

的方法中使用此方法

然后它找到create(n)

中出现的子串的数字

问题是n = 35我没有问题

当我尝试n = 40或50时,我得到一个内存不足的例外而且无法通过增加内存来解决它似乎无法改变算法

这是我的代码:

/* package whatever; // don't place package name! */

import java.util.*;
import java.lang.*;
import java.io.*;

/* Name of the class has to be "Main" only if the class is public. */
public class Kloc
{
    public static String kw(int n)
    {
        if (n == 0)
            return "kake";
        if (n == 1)
            return "echo";
        String n0 = "kake";
        String n1 = "echo";
        String newN = "";
        for ( int i = 2; i<=n;i++)
        {
            newN = n1 + n0;
            n0 = n1;
            n1 = newN;
            System.gc();
        }
        return newN;
    }
    public static void subOccurence(int n, String sub)
    {
        long occurences = 0;
        String kws = kw(n);
        int kwLen = kws.length();
        int subLen = sub.length();
        char subFirstLetter = sub.charAt(0);

        for (int i=0; i<=kwLen-subLen;i++)
        {
            if(kws.charAt(i) == subFirstLetter)
            {
                boolean occurence = true;
                for (int j =0  ; j< subLen; j++ )
                {
                    if(kws.charAt(i+j) != sub.charAt(j))
                    {
                        occurence = false;
                        i = i+j;
                        break;
                    }
                }
                if (occurence)
                    occurences++;
//                if(kws.substring(i,i+subLen).equalsIgnoreCase(sub))
//                {
//                    //System.out .println(kws.substring(i,i+subLen));
//                    occurences++;
//                }
            }
        }
        System.out.println(occurences);
    }

    public static void main (String[] args) throws java.lang.Exception
    {
        // your code goes here
//        subOccurence(40,"kakeecho");
    }
}

2 个答案:

答案 0 :(得分:0)

由于您的实现超出了java中数组的最大限制,因此看起来无法通过增加堆大小来解决此内存不足的原因。

java.util.Arrays.copyOf静态方法的第一步是尝试实例化一个具有存储新字符串所需容量的新数组。当新数组的大小超过数组的最大限制时,这将始终产生令人困惑的内存不足异常。

您遇到的例外情况如下:

out-of-memory: java heap space

有关Java中数组大小的更多信息,请take a look here。看起来这个最大值取决于VM,通常接近 INTEGER.MAX_VALUE

我们可以看到java.utils.Arrays.copyOf方法中发生异常。当java尝试扩展它用于在每次迭代时存储计算字符串的StringBuilder的容量时,就会发生这种情况。在此目前,异常恰好发生在以下行:

newN = n1 + n0;

从一次迭代到另一次迭代,Fibonaci like算法几乎呈指数增长。因此我们可以期待快速达到阵列的最大尺寸

我根据生成的字符串的大小对您的实现进行了投影,以便了解它在每次迭代中的增长量

import java.util.HashMap;
import java.util.Map;

public class FibonaStringSize {
    static Map<Integer, Long> sizeMap = new HashMap<Integer, Long>();
    static {
        sizeMap.put(Integer.valueOf(0), 4L);
        sizeMap.put(Integer.valueOf(1), 4L);
    }
    static long size(int n) {
        if (n == 0) {
            return 4;
        }
        if (n == 1) {
            return 4;
        }

        Long sizeNMin1 = sizeMap.get(Integer.valueOf(n-1));
        Long sizeNMin2 = sizeMap.get(Integer.valueOf(n-2));

        if (sizeNMin1 == null) {
            sizeNMin1 = size(n-1);
            sizeMap.put(Integer.valueOf(n-1), sizeNMin1);
        }

        if (sizeNMin2 == null) {
            sizeNMin2 = size(n-2);
            sizeMap.put(Integer.valueOf(n-2), sizeNMin2);
        }

        return sizeNMin1.longValue() + sizeNMin2.longValue();
    }

    public static void main(String[] args) {
        System.out.println(size(50));
    }
}

这是怎么回事

+--------+-------------+
|   n    |String's size|
+--------+-------------+
|   1    | 4           |
|   10   | 356         |
|   20   | 43784       |
|   30   | 5385076     |
|   40   | 662320564   |
|   50   | 81460044296 |
+--------+-------------+

正如我们所看到的,n=50生成的字符串长度比INTEGER.MAX_VALUE大得多,后者是 2147483647

因此,你应该考虑另一种方法并改变你的算法,否则问题将永远发生。

我非常怀疑采访者是否期望你能够得到确切的解决方案,而是展示出对所用技术的某种程度的掌握以及令人信服的思考,推理和解决问题的方法。如果你再次面对这个问题,你现在做好了准备。

答案 1 :(得分:0)

您应该使用I / O操作进行连接和搜索。通过这种方式,堆空间错误不会发生。以下代码适用于n = 40。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.charset.Charset;

public class Test {

    public static void main(String args[]) throws IOException{

        BufferedReader br = null;

        int limit=40;
        String textToSearch="kakeecho";
        int numberOfOccurence=0;

        try {
            //save each step into a file to avoid java heap space errors.
            PrintWriter writer0 = new PrintWriter("step0.txt", "UTF-8");
            writer0.print("kake");
            writer0.close();

            PrintWriter writer1 = new PrintWriter("step1.txt", "UTF-8");
            writer1.print("echo");
            writer1.close();

            for(int y=2;y<=limit;y++){

                int nextChar;

                PrintWriter writer = new PrintWriter("step"+y+".txt", "UTF-8");
                br = new BufferedReader(new InputStreamReader(
                        new FileInputStream("step"+(y-1)+".txt"),
                        Charset.forName("UTF-8")));

                while((nextChar=br.read())!=-1){
                    writer.print((char)nextChar);
                }

                br.close();

                br = new BufferedReader(new InputStreamReader(
                        new FileInputStream("step"+(y-2)+".txt"),
                        Charset.forName("UTF-8")));

                while((nextChar=br.read())!=-1){
                    writer.print((char)nextChar);
                }

                br.close();

                new File("step"+(y-2)+".txt").delete(); //no need for this file.

                writer.close();

            }

            br = new BufferedReader(new InputStreamReader(
                    new FileInputStream("step"+limit+".txt"),
                    Charset.forName("UTF-8")));

            int ch;
            StringBuilder sb=new StringBuilder();

            while((ch=br.read())!=-1){

                if(sb.toString().length()==textToSearch.length()){

                    if(sb.toString().equals(textToSearch)){
                        numberOfOccurence++;
                    }
                    sb.deleteCharAt(0);

                }

                sb.append((char)ch);

            }

            br.close();

            System.out.println("numberOfOccurence: "+numberOfOccurence);

        } catch (IOException e) {

            e.printStackTrace();

        } finally {

            try {

                if (br != null)
                    br.close();

            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
}