【问题标题】:Find a target value in an unsorted array of integers by performing additions of integers通过执行整数加法在未排序的整数数组中查找目标值
【发布时间】:2013-02-01 03:40:43
【问题描述】:

以下是“亚马逊”向我提出的面试问题。我还没有想出一个优化的解决方案。

问题陈述:
给定一个未排序的整数数组 n。 如果该数组中的任何整数相加目标值相加,则返回“true”,否则返回false

注意:

   1)'n' could be 1000 or 10,000.
   2) Target value could be 'negative'
   3) It may be addition of any 'k' integers (not only two) , where k<=n.  

测试条件:

    i/p:- Array A[]= {6,7,3,0,12,-5,-6,100}
    Target =  8
    o/p:- TRUE        
As, 6+7+(-5)=8

如果我们尝试以线性方式或正常方式进行操作,将花费 O(2^n) 时间复杂度
所以我正在寻找任何可以进一步优化这个问题的方法或算法。

提前谢谢你!

【问题讨论】:

  • “任意两个整数相加”是什么意思?或任何数字?
  • 如果我没听错,你被要求解决subset-sum problem,这是NP-complete。因此,不能合理地期望您比指数时间或伪多项式时间做得更好。
  • 如果是一对整数,我想你的意思是 O(n^2) 时间,而不是 O(2^n)。
  • 很遗憾只有两个人能理解这么清晰的问题。除了@nneonneo 和 kasavbere 之外的每个人都离得很远。人们不再阅读问题了吗?还是他们只是认为他们知道得这么多?
  • @KarthikT 否。可能是添加了“k”个数字,其中 k

标签: c algorithm optimization


【解决方案1】:

子集和问题是众所周知的 NP 完全问题。在这里,我假设您正在寻找任何一组数字来求和到目标(如果您实际上只寻找两个数字,那么有一个使用计数哈希表的五行解决方案,它在 O(n ) 时间)。

有两种基本方法。第一个只是测试每个可能的子序列。正如您已经观察到的那样,这需要 O(2n) 时间(指数),如果 n 为 1000,这是难以处理的。

第二个是跟踪可以从列表的前缀中获得哪些总和。这是一种非常简单的方法,如果整数有界,效果很好。举例来说,如果输入是 n 个 k 位整数,它的计算复杂度为 O(2kn2)(伪多项式):总和可以得到的最大值为 2kn,因此该表最多有 2kn2 个条目。这是一种典型的动态规划方法,其中子问题为T[s][k] = (A[1..k] has a subsequence summing to s),最终解决方案为T[target][n]

这是一个用 Python 实现的解决方案:

def subset_sum(A, target):
    T = {0} # T[s][0] = (TRUE iff s == 0)
    for i in A:
        T |= {x + i for x in T}
    return target in T

例子:

>>> subset_sum([-5,6,7,1,0,12,5,-6,100], 13)
True
>>> subset_sum([95, -120, 22, 14491], 13)
False

奖励:如果您好奇,这里有一个解决对和问题的方法。它在 O(n) 时间内运行并告诉您数组是否有两个数字相加到目标。

from collections import Counter
def pair_sum(A, t):
    C = Counter(A)
    for k,v in C.iteritems():
        if t == k+k and v > 1: return True # k is in the array twice
        elif t != k+k and t-k in C: return True
    return False

例子:

>>> pair_sum([3,3,3,4], 13)
False
>>> pair_sum([3,3,3,10], 13)
True
>>> pair_sum([7,7,2], 14)
True
>>> pair_sum([7,14,2], 14)
False

【讨论】:

    【解决方案2】:

    注意这个答案仍然提供信息,所以我保留它,但在 OP 的编辑之后,它的相关性降低了。

    这是我将如何使用称为“哈希”的概念在 O(n) 运行时复杂度和 O(n) 空间复杂度中解决它的方法。 (其中n是数组的大小)

    让我们拨打我想拨打的号码d

    首先我会创建某种HashTable(键值存储)。 HashMaps 有O(1) 插入、获取和包含。你可以阅读他们here

    然后我会将每个对象放入哈希图中的单元格 d-object 中。在我检查下一个数字 x 之前,我会检查哈希映射是否包含单元格 x 处的值。如果是这样,我们就找到了我们的匹配项。

    这是一些伪代码(我认为这比 C 代码更适合一般性的答案)

    CheckIfTwoNumbersComplementTo(d,arr)
        map <-- new HashTable
        for each number x in Arr
            if(map contains a key for x)
                return true
            else
                add d-x to map if it is not already in map
        return false
    

    【讨论】:

    • 很好,但我敢打赌你的哈希表会占用超过 O(n) 的空间。要获得有效的恒定时间操作,您需要为许多哈希桶分配空间,不是吗?
    • 我的 HashTable 可以在完全 O(n) 空间中实现。我可以简单地分配一个大小为 [n] 的数组并直接将索引用作键:) 我不想在答案中特别建议这一点,因为我想让解决方案尽可能通用。
    • 这仅在问题被更正为:“.. if the added /two/ integers ..”时才有效。此外,确切的 O(n) 没有任何意义,你的意思是确切的 n 空间吗?但是,鉴于您自己的例子,那是完全错误的。数组允许重复,因此假设我们要找到总和 1000,并且我们有一个包含一千个 1s 的数组。与您的方案发生了疯狂的冲突(并且该算法在这种情况下也不起作用,因为它不再是对两个整数求和以找到给定值)。
    • 我认为 OP 是在谈论任何 两个 整数。我的意思是n个空间和n个步骤。我得到重复的那一刻我就完成了,所以我不在乎重复
    • 再说一次,我不明白为什么我应该关心重复,我真的不需要存储 -1 一百万次,我会编辑我的答案以澄清,尽管这是一个好点。
    【解决方案3】:

    如何对数组进行排序,并为每个元素计算目标值所需的对并搜索它?这将使排序的成本 + 加上每个二进制搜索。

    【讨论】:

    • 所以这将是 O(n log n) 时间。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-06
    • 2014-05-13
    • 1970-01-01
    • 2021-04-30
    • 2012-11-17
    相关资源
    最近更新 更多