【问题标题】:Sorting result array排序结果数组
【发布时间】:2010-12-29 05:01:27
【问题描述】:

我在 Adob​​e 面试中被问到这个问题:

我们有一个按升序排序的整数数组。我们还有 3 个整数 ABC。我们需要为数组中的每个元素x申请A*x*x + B*x + C,并返回对应的排序后的数组。

给我的例子:

Input array = -1 0 1 2 3 4
A = -1, B = 2, C = -1`

将公式应用于每个元素的结果 = -4 -1 0 -1 -4 -9
所以预期结果 = -9 -4 -4 -1 -1 0(已排序)

我最好的解决方案是应用公式并对其进行排序,从而得到O(nlogn) 解决方案。我不能做得更好。

任何改进它的指导都是有帮助的。

【问题讨论】:

  • 按 O(logN) 时间排序??不可以,应该是 O(N*LogN) 时间......从数学上证明,你不能在小于 O(NLogN) 的时间内对随机数集合进行排序
  • 他期待 O(N) 解决方案。
  • @birryree:你必须利用这种情况的特殊性来意识到O(n) 是可能的。此外,元推理表明这个问题并不有趣,除非答案不是O(n log n)
  • @birryree:当回复出现建议不那么出色的评论时删除 cmets 是蹩脚的。
  • @user556744:不要误会,这是对未来面试的真诚建议。您的解决方案简单了。任何在算法课程中有过感触的人都可以想出它。这表明必须有一个更好的解决方案,或者这是一个糟糕的面试问题(因为否则它不会过滤好坏)。因为这不太可能是一个糟糕的面试问题,所以必须有一个更好的解决方案。此外,您没有使用转换是抛物线这一事实(它可能是 anything 并且您的解决方案仍然有效)。这表明您忽略了一些重要的事情。

标签: arrays algorithm sorting


【解决方案1】:

给出的等式是parabolic。因此,将其应用于排序数组的结果将产生一个数组,该数组将具有最大值/最小值,其左右的子数组已排序。

在您的情况下,最大值为0,其左侧的子数组[-4 -1]按升序排序,其右侧的子数组[-1 -4 -9]按降序排序。

您需要做的就是合并这些排序后的数组,这在时间上是线性的。

所以算法是:

  1. 对每个元素应用方程
  2. 查找最大值/最小值
  3. 合并子数组

【讨论】:

    【解决方案2】:

    您可以在O(n) 中执行此操作。求多项式的最小值发生在什么时候

    2 * A * x + B = 0
    

    这样

    x_min = -B / 2 * A.
    

    然后,遍历数组,直到找到最接近x_min 的整数。这是O(n)。从这里开始,根据|x_min - left| 是否小于或大于|x_min - right|,从该元素的左侧或右侧依次选择。按结果顺序返回在这些点处评估多项式的​​值。这是O(n)

    这假设A 是正数。否定A的情况同样可以处理。

    例子:

    input array = -1 0 1 2 3 4 A = -1, B = 2, C = -1
    

    这里,最大值出现在x_max = -2 / 2 * -1 = 1。从输入数组中,最接近的值是第三个元素1。然后我们根据它们到1的距离依次按以下顺序挑选元素。

    1, 0, 2, -1, 3, 4
    

    然后,因为A 是负数,我们必须以相反的顺序运行这些

    4, 3, -1, 2, 0, 1
    

    并评估它们的多项式

    -9, -4, -4, -1, -1, 0
    

    完成。

    请注意,我们正在利用抛物线的特殊性质。即,对于x 小于x_extremeA 为正,将多项式应用于此类xx 的递减函数。对于大于x_extremeA 正的x,将多项式应用于此类xx 的递增函数。 (如果A 为负数,也适用类似的推理。)因此,将数组分成两部分,x 小于x_extremex 大于x_extreme。然后将多项式应用于这两个部分,最终得到两个排序的数组。现在将合并排序应用于这些排序数组。请注意,上面的描述实际上是归并排序。

    【讨论】:

    • 非常感谢您提供详细示例。
    • 您的解决方案是最直观的解决方案,但实际上不需要在我们的数据数组中找到最小值/最大值。我们只是立即从末端开始,但可能希望检查每个点的一阶导数,看看我们是否跨越它或者我们的数组是否已经排序。
    【解决方案3】:

    解决方案是O(N),虽然有助于理解曲线的形状,但无需执行任何微积分。

    上面的答案是做最直观的事情,解方程找到最小值或最大值,然后拆分列表。

    计算一阶导数是有好处的,但实际上不需要这样做,此时我们也不需要找到最大值或最小值。

    只要知道它可以朝一个方向移动,然后再朝另一个方向返回,但永远不会改变方向超过一次。

    我们将从每一端开始,从两边迭代,直到我们在中间的某个地方合并。在我们做任何其他事情之前,我们需要检查每一端的方向,我们将通过比较结束的两个元素来做到这一点。所以我们看看是一端向上移动,另一端向下移动。

    如果我们有N 元素,假设我们有数据X[0]X[N-1],那么计算f(X[0])f(X[N-1])f(X[1])f(X[N-2])。如果f(X[0]) < f(X[1])f(X[N-1]) > f(X[N-2]) 那么实际上我们所有的数据都是最大值/最小值的一侧,因此已经排序。如果比较是在另一个方向上,则相同。 (一个方向可能需要反向)。

    否则只需从两端执行合并,因此f(X[0])f(X[N-1]) 是它们子范围的最大值或最小值(我们从前面的比较中知道)并从适当的方向创建合并列表。

    应用于您的数据:

    -1 0 1 2 3 4
    A = -1, B = 2, C = -1`
    
    f = [ -4, -1, 0, -1, -4, -9 ]
    

    -4 < -1-9 < -4 所以我们确实越过了点,我们在每一端都有最小值。

    -9 is lower than -4
    -4 and -4 are equal so push both
    -1 and -1 are equal so push both
    0 remains.
    
    our sequence is [-9, -4, -4, -1, -1, 0 ]
    

    【讨论】:

      【解决方案4】:

      您可以认识到将二次方应用于数据的结果几乎是排序的(如上面的答案中所述,或者通过认识到 n 次多项式的导数是连续的、n - 1 次的,并且具有最多 n 个零)。

      因此,如果您的库中有一个排序例程可以巧妙地处理几乎已排序的数据(例如记住这一点的合并排序),您可以将数据扔给它并期望线性性能。在网上搜索发现Which sort algorithm works best on mostly sorted data? 指向http://svn.python.org/projects/python/trunk/Objects/listsort.txt

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-30
        • 2020-05-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多