【问题标题】:Find pair of indices given coordinates and values查找给定坐标和值的索引对
【发布时间】:2021-05-31 22:52:59
【问题描述】:

我有一个问题如下。我知道使用 2 个循环的 O(n^2) 解决方案,但是是否有解决方案可以在线性时间内解决它?

给定坐标 x 为 x1, x2....,xn 和与每个坐标关联的值 p 为 p1, p2,...,pn,找到索引 (i,j) 使得 pi + pj + |xj - xi| 是最大值,而 |x| 是绝对值。

例如:

(x1, p1) = (5, 10)
(x2, p2) = (3, 20)
(x3, p3) = (12, 5)
The answer is (2,3).

【问题讨论】:

  • O(n) 非常渴望。我什至会很高兴找到一个 O(n logn) 算法。
  • 我认为应该有一些 O(n logn) 解决方案。直觉是:对 对的列表进行排序,使索引 ij 位于列表的开头和结尾(排序后)。

标签: arrays algorithm optimization


【解决方案1】:

如果我们观察以下情况,我们可以找到 O(n) 解决方案:

  • 如果(i, j)pi - xi 最大且pj + xj 最大的索引,那么(i, j) 就是pi + pj + |xj - xi| 最大的索引

证明:由于pi + pj + |xj - xi|等于(pi - xi) + (pj + xj)(pj - xj) + (pi + xi),当我们交换ij时,(pj - xj) + (pi + xi)变为(pi - xi) + (pj + xj),最大pi + pj + |xj - xi| 的值小于或等于(pi - xi) + (pj + xj) 的最大值。所以现在只要证明(pi - xi) + (pj + xj) 等于pi + pj + |xj - xi| 就足够了,(pi - xi) 是最大值,(pj + xj) 是最大值,因此(pi - xi) + (pj + xj) 是最大值。如果pi - xi 是最大值,pj + xj 是最大值,则(pi - xi) + (pj + xj) 是最大值。还有xj - xi >= 0 持有。 (否则,如果 xj - xi < 0(pi - xi) + (pj + xj) < (pj - xj) + (pi + xi)pi - xi < pj - xjpj + xj < pi + xipi - xipj + xj 是最大值相矛盾。)因此,(pi - xi) + (pj + xj) = pi + pj + |xj - xi|(i, j) 是最大化它的索引。


因此,为了最大化pi + pj + |xj - xi|,我们只需要找到分别最大化pi - xipj + xj 的索引(i, j)

这是微不足道的

  • 可以在 O(n) 中找到最大化 pi - xi 的索引 i
  • 可以在 O(n) 中找到最大化 pj + xj 的索引 j

因此,作为答案的索引(i, j) 可以在 O(n) + O(n) = O(n) 中找到。

用python编写的完整解决方案如下。 (您似乎还假设i != j,因为否则示例答案将是(2, 2),而不是(2, 3)。因此添加了一些代码以确保添加了i != j。)

# Time complexity: O(n) where n is len(t_p) or len(t_x)
def get_argmax(t_p, t_x, operator, excluded_index=None):
    max = -float('inf')
    argmax = None
    for i, (p, x) in enumerate(zip(t_p, t_x)):
        if i == excluded_index:
            continue
        if operator(p, x) > max:
            max = operator(p, x)
            argmax = i
    return argmax


# get the answer indices (i, j)
# which maximizes t_p[i] + t_p[j] + |t_x[j] - t_x[i]|
# in time complexity O(n) where n is len(t_x) or len(t_p)
def get_answer(t_x, t_p):
    argmax_i = get_argmax(t_p, t_x, lambda a, b: a - b)  # O(n)
    argmax_j = get_argmax(t_p, t_x, lambda a, b: a + b)  # O(n)
    answer = (argmax_i, argmax_j)

    # The if statement below is for to make sure that argmax_i != argmax_j
    if argmax_i == argmax_j:
        second_argmax_i = get_argmax(t_p, t_x,
                                     lambda a, b: a - b, argmax_i)  # O(n)
        second_argmax_j = get_argmax(t_p, t_x,
                                     lambda a, b: a + b, argmax_j)  # O(n)
        max1 = (t_p[argmax_i] - t_x[argmax_i]) + (t_p[second_argmax_j] +
                                                  t_x[second_argmax_j])
        max2 = (t_p[second_argmax_i] - t_x[second_argmax_i]) + (t_p[argmax_j] +
                                                                t_x[argmax_j])
        if max1 >= max2:
            answer = (argmax_i, second_argmax_j)
        else:
            answer = (second_argmax_i, argmax_j)

    return answer


if __name__ == '__main__':
    t_x = [5, 3, 12]
    t_p = [10, 20, 5]

    answer = get_answer(t_x, t_p)

    answer_one_based_index = (answer[0] + 1, answer[1] + 1)
    print(f'The answer is {answer_one_based_index}.')

打印出来:

The answer is (2, 3).

【讨论】:

  • 我认为你需要最大化 |pi - xi|而不仅仅是 pi-xi。
  • @maddy 你能告诉我原因吗?在我的帖子中,我解释说,要最大化 pi + pj + |xj - xi|,只需 最大化 pi + pj + xj - xi,它等于 (pj + xj) + (pi - xi)。所以我们只需要分别最大化pj + xjpi - xi
  • @maddy 再次阅读我的帖子后,我意识到我的写作并不是那么容易理解。所以我加强了写作,使它比以前更清晰。感谢您的评论!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-06
  • 1970-01-01
  • 2013-01-09
  • 1970-01-01
  • 2021-11-01
  • 2016-09-11
  • 1970-01-01
相关资源
最近更新 更多