给定一个整数数组,使用数组的数字找到LARGEST数字,使其可被3整除

时间:2012-09-19 11:14:02

标签: algorithm dynamic-programming greedy

例如:数组:4,3,0,1,5 {假设所有数字都是> = 0。数组中的每个元素也对应一个数字。即阵列上的每个元素都在0到9之间。}

在上面的数组中,最大的数字是:5430 {使用数组中的数字5,4,3和0}

我的方法:

对于3的可分性,我们需要数字的总和可以被3整除。 所以,

  1. 步骤1:从阵列中删除所有零。
  2. 步骤2:这些零将在最后出现。 {因为他们不会影响总和,我们必须找到最大的数字}
  3. 步骤3:找到数组元素的子集(不包括零),使得位数为MAXIMUM,并且数字之和为MAXIMUM,总和可以被3整除。
  4. 步骤4:所需数字由上面找到的数字按降序排列。
  5. 因此,主要步骤是STEP-3,即如何找到子集,使其包含MAXIMUM可能数量的元素,使得它们的和为MAX,并且可以被3 整除。

    我在想,也许Step-3可以通过GREEDY CHOICE来完成所有元素并继续删除集合中的最小元素,直到总和可以被3整除。

    但我不相信这个贪婪的选择会奏效。

    请告诉我的方法是否正确。 如果是,那么请建议如何做第3步?

    另外,请建议任何其他可能/有效的算法。

6 个答案:

答案 0 :(得分:17)

观察:如果你能得到一个可被3整除的数字,你需要删除最多2个数字,以保持最佳解决方案。

一个简单的O(n^2)解决方案是检查删除1个数字的所有可能性,如果没有效果,请检查所有对(这些对中有O(n^2)个。)


修改
O(n)解决方案:创建3个存档桶 - bucket1bucket2bucket0。每个都表示数字的模数3值。在下一个算法中忽略bucket0

让数组之和为sum

If sum % 3 ==0: we are done.
else if sum % 3 == 1:
  if there is a number in bucket1 - chose the minimal
  else: take 2 minimals from bucket 2
else if sum % 3 == 2
  if there is a number in bucket2 - chose the minimal
  else: take 2 minimals from bucket1  

注意:您实际上不需要存储桶来实现O(1)空间 - 您只需要来自bucket1bucket2的2个最小值,因为它是我们唯一的数字实际上是从这些桶中使用的。

示例:

arr = { 3, 4, 0, 1, 5 }
bucket0 = {3,0} ; bucket1 = {4,1} bucket2 = { 5 }
sum = 13 ; sum %3 = 1
bucket1 is not empty - chose minimal from it (1), and remove it from the array.
result array = { 3, 4, 0, 5 } 
proceed to STEP 4 "as planned"

答案 1 :(得分:5)

贪婪的选择肯定不起作用:考虑集合{5, 2, 1}。您先删除1,但应删除2

我认为你应该算出数组模3的总和,它是0(你已经完成),或者是1或2.然后你想要删除其模3的总和为1的最小子集或2.

我认为这很简单,所以不需要动态编程。如果可能的话,通过删除具有该模数的一个数字来执行此操作,否则通过使用其他模数移除两个数字来执一旦知道要移除多少,请选择尽可能小的。你永远不需要删除三个数字。

您不需要特别对待0,但如果您要这样做,那么如果暂时删除所有0,3,6,9,您可以进一步减少步骤3中考虑的设置从它。

总而言之,我可能会:

  • 对数字进行排序,降序。
  • 计算模量。如果为0,我们就完成了。
  • 尝试从结尾开始删除具有该模数的数字。如果成功,我们就完成了。
  • 从结尾开始删除负数模数的两位数字。这总是成功的,所以我们已经完成了。
  • 我们可能会留下一个空数组(例如,如果输入是1, 1),在这种情况下问题是不可能的。否则,数组包含结果的数字。

时间复杂度为O(n),前提是您在步骤1中进行了计数排序。由于值是数字,您当然可以这样做。

答案 2 :(得分:1)

您如何看待这个:

首先按值排序数组元素

sum up all numbers
- if sum's remainder after division by 3 is equal to 0, just return the sorted
  array
- otherwise
    - if sum of remainders after division by 3 of all the numbers is smaller
      than the remainder of their sum, there is no solution
    - otherwise
        - if it's equal to 1, try to return the smallest number with remainder
          equal to 1, or if no such, try two smallest with remainder equal to 2,
          if no such two (I suppose it can happen), there's no solution
        - if it's equal to 2, try to return the smallest number with remainder
          equal to 2, or if no such, try two smallest with remainder equal to 1,
          if no such two, there's no solution

首先按除以3的余数对数组元素进行排序 那么相等余数的每个子集按值降序排序

答案 3 :(得分:1)

首先,这个问题减少到最大化所选元素的数量,使得它们的总和可被3整除。

琐碎:选择所有可被3整除的数字(0,3,6,9)。

Le a是将1作为余数的元素,b是将2作为余数的元素。如果(| a | - | b |)%3为0,则从a和b中选择所有元素。如果(| a | - | b |)%3为1,则从b中选择所有元素,从a中选择| a | -1最高数字。如果余数为2,则从a中选择所有数字,从b中选择| b | -1最高数字。

获得所有数字后,按相反​​的顺序对它们进行排序并连接。这是你的答案。

最终,如果n是元素的数量,则该算法返回的数字至少为n-1位数(除了极端情况。见下文)。

注意:注意角落情况(即什么是| a | = 0或| b | = 0等)。 (-1)%3 = 2且(-2)%3 = 1。

如果m是字母表的大小,而n是元素的数量,那么我的算法是O(m + n)

答案 4 :(得分:0)

不需要对数据进行排序,因为只有十个不同的值。 如果给出n位数,只需计算O(n)中的零,一,二等数。 计算所有数字的总和,检查模3的余数是0,1或2.

如果余数为1:删除可能的下列第一个(保证其中一个可能):1,4,7,2 + 2,2 + 5,5 + 5,2 + 8 ,5 + 8,8 + 8。

如果余数为2:删除以下第一个可能的(保证其中一个可能):2,5,8,1 + 1,1 + 4,4 + 4,1 + 7 ,4 + 7,7 + 7。

如果没有数字,则问题无法解决。否则,解决方案是通过连接9,8,7和7等来创建的,依此类推。

(对n个数字进行排序需要O(n log n)。除非你按照每个数字出现的频率进行排序并根据这些数字生成排序结果。

答案 5 :(得分:0)

阿米特的回答有点遗漏。

如果bucket1不是空但它有一个巨大的值,让我们说79和97并且b2也不是空的,它的2个最小值是,例如2和5.然后在这种情况下,当模数总和时所有数字都是1,我们应该选择从桶2中删除2和5而不是桶1中的最小值来获得最大的连接数。

测试案例:8 2 3 5 78 79

如果我们遵循Amits和Steve建议的方法,最大数字将是878532,而此数组中可能除以3的最大数字是879783

解决方案是将适当的桶的最小最小值与另一个桶的最小值的串联进行比较,并消除较小的桶。