【问题标题】:Looking for efficient algorithm to find nearest integer in a list of integers寻找有效的算法以在整数列表中找到最接近的整数
【发布时间】:2012-02-29 15:33:13
【问题描述】:

情况是这样的。我有一个排序的整数列表,表示需要在特定毫秒触发的事件。该列表可能如下所示:

0
1500
5000
9348
89234
109280
109281
109283
150000

然后我有一个playhead,它通常每 100 毫秒向前移动一次,但也可以随机搜索和向前和向后擦洗。该播放头不能保证是 100 的倍数,但可以降到该倍数而没有任何实际问题。

我的挑战是能够有效地找到列表中小于或等于当前播放头的最近元素。列表的平均长度在 300 到 1500 个元素之间。我可以很容易地以设定的时间间隔进行优化,但随机搜索要复杂一些。

让我真希望我没有在算法课上睡觉。

【问题讨论】:

  • 最简单的方法:向后循环数组并选择小于或等于播放头的第一个元素。你试过了吗,这对你的用例来说效率太低了吗?
  • 挑战在于有效地找到...线性搜索效率不高。
  • 它可能足够高效。对于现代机器来说,1500 个元素并不是那么多
  • 线性搜索是我们现在所做的。 1500不算多,但是在浏览器播放视频的JS中的1500有点不一样。

标签: javascript list integer


【解决方案1】:

我前段时间遇到过这个问题,并做了一些执行时间比较。

看看here。 (该示例不适用于 IE)

与愚蠢的二分搜索相比,第四个实现似乎真的很规则。

希望对你有帮助。

再见

【讨论】:

    【解决方案2】:

    听起来您想要修改后的二进制搜索。由于列表是按排序顺序排列的,因此二进制搜索将大大提高线性搜索的搜索性能,并且如果您对数组中项目的间距一无所知,那么您无法比二进制搜索做得更好。二进制搜索需要稍作修改,因为您不是在寻找相等性,而是在不超过的情况下寻找接近的东西。

    这是一个实际的算法,它将搜索数据分成 1/2(根据与测试值的比较,每次使用上半部分或下半部分),直到它只剩下一个元素:

    var testData = [0,1500,5000,9348,89234,109280,109281,109283,150000];
    
    function findNearest(data, val) {
        if (!data || !data.length) {
            return(null);
        }
        var lowest = 0, mid;
        var highest = data.length - 1;
        while (true) {    
            if (lowest == highest) {
                return(lowest);
            }
            mid = Math.ceil(((highest - lowest) / 2) + lowest);
            if (data[mid] == val) {
                return(mid);
            }
            else if (data[mid] < val) {
                lowest = mid;
            } else {
                highest = Math.max(lowest, mid - 1);
            }
        }
    }
    

    还有一个工作测试程序:http://jsfiddle.net/jfriend00/rWk2X/

    注意:此代码假定数组中的所有值均已排序且数组不为空。

    如果你给它一个没有值小于目标值的数组,它将返回 0,这可能是你需要处理的特殊情况,除非确定数组中的第一个值总是小于目标值(例如始终为零)。

    如果你给它一个没有大于目标值的值的数组,它将返回数组中的最后一个值(应该如此),这不是特殊情况,只是想要的答案。

    【讨论】:

    • 由于这似乎是一个有趣的算法问题,我在答案中添加了一个工作代码示例。如果你玩这个,要小心,因为它很容易陷入无限循环。实际上,为了避免无限循环,我在测试期间将最大次数的迭代编码到我的代码中(它会在 1000 次迭代后中止并出现错误)。
    • 这看起来是最好的解决方案。是否有一组特定的输入会导致无限循环?
    • @turing1 - 输入不会导致无限循环。您可以传入任何内容,并且在代码尝试解释之后,它可以很好地处理为 cmets。仅当您弄乱了函数中的代码并将其搞砸时,您才会面临无限循环的风险。
    【解决方案3】:

    因为它是一个排序列表,所以使用二进制搜索。你可以做得更好,但是你必须做出额外的假设(例如,你必须假设数字的均匀分布,我认为情况并非如此)。你可以在这里阅读:http://en.wikipedia.org/wiki/Binary_search_algorithm

    【讨论】:

      【解决方案4】:

      我认为Divide and conquer algorithm 是最合适的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-08-09
        • 1970-01-01
        • 2010-11-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多