用于查找满足gt(大于条件)最快的数字的算法

时间:2013-12-11 17:28:52

标签: algorithm

我必须检查一个数字会导致某种类型溢出的临界点。

如果我们假设溢出数是98,那么一个非常低效的方法是从1开始并一次增加1。这需要进行98次比较。

我这样做了一个更好的方法

在一个已知的失败条件之后它基本上将检查更改为下一个2的幂,例如我们知道0失败所以我们开始检查1,然后是2,4,8,...,128。 128次通过所以我们检查64 + 1,64 + 2,64 + 4,...,64 + 32,但是我们知道64 + 16失败所以我们开始下一轮1+(64 + 16)= == 1 + 80。这是一个视觉:

1   1
2   2
3   4
4   8
5   16
6   32
7   64
81  128 ->
9          1, 64 // 1 + 64
10         2, 64
11         4, 64
12         8, 64
13         16, 64
14         32, 64 ->
15                  1, 80
16                  2, 80
17                  4, 80
18                  8, 80
19                  16, 80
20                  32, 80 ->
21                            1, 96
22                            2, 96 // done

有没有更好的方法呢?

3 个答案:

答案 0 :(得分:2)

如果您不知道最大数量,我认为按照您的初始方法找到MIN = 64,MAX = 128范围是好的。在找到最小值/最大值后进行二分搜索将是最有效的(例如,查看96,如果它导致溢出,那么您知道范围是MIN = 64,MAX = 96)。你将每一步的范围减半,你会更快地找到解决方案。

由于你的答案是98,所以这就是如何通过二分搜索来实现的。这需要13步而不是22步:

// your initial approach
1   1
2   2
3   4
4   8
5   16
6   32
7   64
8   128 ->
// range found, so start binary search
9          (64,128) -> 96
10                  (96,128) -> 112
11                          (96,112) -> 104
12                                 (96,104) -> 100
13                                        (96,100) -> 98 // done
// you may need to do step 14 here to validate that 97 does not cause overflow
// -- depends on your exact requirement

答案 1 :(得分:1)

如果你知道“溢出函数”是单调递增的,你可以继续加倍,直到你完成,然后应用经典的二进制搜索算法。这将为您提供以下搜索序列:

1
2
4
8
16
32
64
128 -> over - we have the ends of our range

[64..128]范围

中运行二进制搜索
64..128, mid = 96
96..128, mid = 112
96..112, mid = 104
96..104, mid = 100
96..100, mid = 98
96..98,  mid = 97
97 - no overflow ==> 98 is the answer

答案 2 :(得分:1)

以下是我在javascript中实现此技术的方法:

function findGreatest(shouldPassCallback) {
    function findRange(knownGood, test) {
        if (!shouldPassCallback(test)) {
            return [knownGood, test];
        } else {
            return findRange(test, test * 2);
        }
    }
    function binarySearchCompare(min, max) {
        if (min > max) {
            throw 'Huh?';
        }
        if (min === max) { return shouldPassCallback(min) ? min : min - 1; }
        if (max - min === 1) { return shouldPassCallback(max) ? max : min }
        var mid = ~~((min + max) / 2);
        if (shouldPassCallback(mid)) {
            return binarySearchCompare(mid, max);
        } else {
            return binarySearchCompare(min, mid);
        }
    }
    var range = findRange(0, 1);
    return binarySearchCompare(range[0], range[1]);
}