我必须检查一个数字会导致某种类型溢出的临界点。
如果我们假设溢出数是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
有没有更好的方法呢?
答案 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]);
}