Java操纵大位数

时间:2012-02-18 04:38:56

标签: java

我一直在我的业余时间工作面试街挑战改变比赛一个多星期,现在只是旋转我的车轮,所以我希望有人可以给我一个指针或提示正确的方向。

挑战的基础是采取两个字符串A& B并运行一些操作两位字符串的查询。

设A和B为两个N位数。您将获得A和B的初始值,您应该编写一个处理三种查询的程序:

  • set_a idx x:将A [idx]设置为x,其中0 <= idx&lt; N,其中A [idx]是 idx'th最重要的一点。
  • set_b idx x:将B [idx]设置为x,其中0 <= idx&lt; Ñ
  • get_c idx:打印C [idx],其中C = A + B,0 <= idx

其中位数的长度为1到100,000,并且程序可以包含set_a,set_b或get_c的任意组合的1到500,000个查询。

为了最小化循环,我使用C作为运行总计。当A或B中的位改变时,也从C加上或减去改变的位。当存在进位时,进一步最小化加法和减法时的循环从改变的位到左手完成。

private static void add(final boolean[] the_array, final int the_index)
{
    for(int iter = the_array.length - the_index - 1; iter >= 0; iter--)
    {
        if(the_array[iter])
        {
            the_array[iter] = false;
        }
        else if(!the_array[iter])
        {
            the_array[iter] = true;
            return ;
        }
    }
}

private static void subtract(final boolean[] the_array, final int the_index)
{
    for(int iter = the_array.length - the_index - 1; iter >= 0; iter--)
    {
        if(the_array[iter])
        {
            the_array[iter] = false;
            return ;
        }
        else if(!the_array[iter])
        {
            the_array[iter] = true;
        }
    }
}

整体而言,该程序运行良好,完成了最大边缘长度为100,000的情况,500,000个查询在大约120ms内运行但是仍然不够快,无法应对挑战。由于比特长度的大小快速超过Java中的原始整数(长)值,因此大多数API不适用于此。由于我没有取得多大进展,因此整体运行时间的大小开始表明可能存在一种算法或数据结构,而不仅仅是一个数组。有什么想法吗?

2 个答案:

答案 0 :(得分:3)

嗯,离开我的头顶:
不要保持C周围/更新,只需计算你在飞行中要求的位。请记住,当您添加A和B的相应位位置时,您只需要查看相邻的较低有效位,直到找到它们都为零的点 - 除此之外的任何位置都不能传输经过它的位。 e.g。

A: 001101001010111
B: 010110100010110
     ^ asked for C there
   1000111^ only need to add bits from here
     ^ until you get your answer.

答案 1 :(得分:2)

我会使用long []而不是boolean []。每个long都有64位,您可以执行组合操作,如

if (the_array[iter] == -1L) // all 1s
    the_array[iter] = 0L; // all zeros.

您可以在与布尔操作大致相同的时间内执行64位操作,从而使循环速度提高64倍。

BTW:使用boolean[]将使用8倍于long[]的内存,因为每个boolean在大多数JVM中使用一个字节的内存。


使用较长类型存储数据的示例。

根据您的效果,使用int可以更轻松地进行操作,例如x = (long) a * b会溢出long但不会int

如果您正在扫描大量位(如BitSet可以做的那样),那么使用long[]会更快。


添加一个基准,显示它可以做出的时间差异。

public static final int RUNS = 100;

public static void main(String... args) throws InterruptedException {
    boolean[] bools = new boolean[1024 * 1024];
    long[] longs = new long[bools.length / 64];

    for (int i = 0; i < 5; i++) {
        testBools(bools);
        testLongs(longs);
    }
}

private static void testBools(boolean[] bools) {
    long start = System.nanoTime();
    for (int t = 0; t < RUNS; t++) {
        // set all to true
        for (int i = 0; i < bools.length; i++)
            bools[i] = true;
        // search for a false;
        for (boolean b : bools)
            if (!b) throw new AssertionError();

        // set all to false
        for (int i = 0; i < bools.length; i++)
            bools[i] = false;
        // search for a true;
        for (boolean b : bools)
            if (b) throw new AssertionError();
    }
    long time = System.nanoTime() - start;
    System.out.printf("To set and scan a boolean[] with %,d bits took %,d us%n",
            bools.length, time / 2/ RUNS / 1000);
}

private static void testLongs(long[] longs) {
    long start = System.nanoTime();
    for (int t = 0; t < RUNS; t++) {
    // set all to true
    for (int i = 0; i < longs.length; i++)
        longs[i] = ~0; // all 1s
    // search for a false;
    for (long l : longs)
        if (l != ~0) throw new AssertionError();

    // set all to false
    for (int i = 0; i < longs.length; i++)
        longs[i] = 0; // all 0s

    // search for a true;
    for (long l : longs)
        if (l != 0) throw new AssertionError();
    }
    long time = System.nanoTime() - start;
    System.out.printf("To set and scan a long[] with %,d bits took %,d us%n",
            longs.length * Long.SIZE, time / 2/ RUNS / 1000);
}

打印

To set and scan a boolean[] with 1,048,576 bits took 777 us
To set and scan a long[] with 1,048,576 bits took 104 us
To set and scan a boolean[] with 1,048,576 bits took 666 us
To set and scan a long[] with 1,048,576 bits took 20 us
To set and scan a boolean[] with 1,048,576 bits took 537 us
To set and scan a long[] with 1,048,576 bits took 18 us
To set and scan a boolean[] with 1,048,576 bits took 567 us
To set and scan a long[] with 1,048,576 bits took 28 us
To set and scan a boolean[] with 1,048,576 bits took 776 us
To set and scan a long[] with 1,048,576 bits took 27 us

在此示例中,与boolean[]

相比,使用long[]的速度要慢30倍