java - 递归 Karatsuba 乘法不起作用?

标签 java algorithm recursion

我正在尝试实现 Karatsuba multiplication通过递归调用。下面的代码应该可以工作,但我总是得到错误的答案。有什么想法吗?

    public static long karatsuba(long x, long y){
        //base case:
        if (x < 10 || y < 10) return x * y;

        //length of digits:
        int xSize = String.valueOf(x).length();
        int ySize = String.valueOf(y).length();
        int N     = Math.max(xSize, ySize);

        //split each number in half (by length of digits):
        long numX_hi = Long.valueOf((String.valueOf(x).substring(0, N/2)));
        long numX_lo = Long.valueOf((String.valueOf(x).substring(N/2, xSize)));
        long numY_hi = Long.valueOf((String.valueOf(y).substring(0, N/2)));
        long numY_lo = Long.valueOf((String.valueOf(y).substring(N/2, ySize)));

        //solve multiplications recursively:
        long z0 = karatsuba(numX_lo,numY_lo);
        long z1 = karatsuba((numX_hi+numX_lo),(numY_hi+numY_lo));
        long z2 = karatsuba(numX_hi,numY_hi);

        //answer:
        return  (long)(z2 * Math.pow(10,N))  +  (long)((z1-z2-z0) * Math.pow(10,(N/2)))  +  (z0);
    }

下面是一些测试用例:

1) karatsuba(1234,5678) >>> 6952652

*应该是7006652

2) karatsuba(4589, 7831) >>> 34649459

*应该是35936459

3) karatsuba(911, 482) >>> 44722

*应该是472842

最佳答案

您的方法有两个明显的问题。

首先,您应该从最后一位(最低有效位)开始拆分,而不是从第一位开始。所以如果你有这两个数字:

1234
567890

你目前是这样拆分它们的:

123   4 (123*1000+4)
567 890 (567*1000+890)

这会让您得到错误的结果,因为 1234 != 123*1000+4

你应该像这样拆分它们:

  1 234  (1*1000+234)
567 890  (567*1000+890)

我发现的第二个错误发生在您将事物重新组合在一起时。

return  (long)(z2 * Math.pow(10,N))  +  (long)((z1-z2-z0) * Math.pow(10,(N/2)))  +  (z0);

对于奇数 N 将返回不正确的结果,因为 N/2 将被向上向下舍入,因此 N ! = ((N/2)*2)

我结合了这两个修复,现在我得到了正确的结果:

public static long karatsuba(long x, long y){
    //base case:
    if (x < 10 || y < 10) return x * y;

    //length of digits:
    int xSize = String.valueOf(x).length();
    int ySize = String.valueOf(y).length();
    int halfN     = Math.max(xSize, ySize) / 2; // store N/2 instead of N
    int splitX = xSize - halfN;  // count the split point from xSize down
    int splitY = ySize - halfN;  // count the split point from ySize down

    //split each number in half (by length of digits):
    long numX_hi = Long.valueOf((String.valueOf(x).substring(0, splitX)));
    long numX_lo = Long.valueOf((String.valueOf(x).substring(splitX)));
    long numY_hi = Long.valueOf((String.valueOf(y).substring(0, splitY)));
    long numY_lo = Long.valueOf((String.valueOf(y).substring(splitY)));

    //solve multiplications recursively:
    long z0 = karatsuba(numX_lo,numY_lo);
    long z1 = karatsuba((numX_hi+numX_lo),(numY_hi+numY_lo));
    long z2 = karatsuba(numX_hi,numY_hi);

    //answer:
    return  (long)(z2 * Math.pow(10,halfN*2))  +  (long)((z1-z2-z0) * Math.pow(10,halfN))  +  (z0);
}

关于java - 递归 Karatsuba 乘法不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28233748/

相关文章:

c - 查找步骤以找到给定的索引值

algorithm - 为什么深度优先搜索的空间复杂度不用O(n)表示?

c - 用于查找数字阶乘的递归函数

c++ - 递归和函数 c++

java - 为什么我的 Elasticsearch 集成测试有时只能工作

java - log4j:文件已创建但未写入

java - 从文件中读取按钮名称

python - 在 Python 中使用 Networkx 从 DAG 中查找最长的加权路径?

r - 使用 R 中的 Ackermann 函数避免堆栈溢出

java - 如何解决android studio中的守护进程配置错误