【问题标题】:Given an array of integers, find the LARGEST number using the digits of the array such that it is divisible by 3给定一个整数数组,使用数组的位数找到最大的数,使得它可以被 3 整除
【发布时间】:2012-09-11 16:42:02
【问题描述】:

例如:数组: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. STEP-4:所需数字由上述找到的数字按降序排列。

因此,主要步骤是第 3 步,即 如何找到子集,使其包含最大可能数量的元素,使得它们的总和为 MAX 并且可被 3 整除

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

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

请告诉我的方法是否正确。 如果是,请建议如何执行步骤3?

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

【问题讨论】:

  • 暴力生成所有可能性怎么样?即生成所有能被3整除的组合,然后取最大的?
  • 第 3 步有点类似于 subset-sum problem,但它也更容易闻起来(因此它可能是多项式可解的)。但我怀疑贪婪在这里会起作用。
  • @ClemKeirua :是的,蛮力总是一种选择。但我在想是否可以以某种有效的方式完成。
  • @amit:如果我们使用子集和方法,那么我们将不得不考虑 3 的所有倍数:3、2*3、3*3、4*3 ......等等。 . 所以我猜那只会变成指数级。
  • 这是我的想法:您删除零,如您所说,它们将被添加到末尾。剩下 N 个非零数字然后您生成具有最大长度 N 的所有可能性。如果您找到某些东西,则取最大值。也许按降序对数字进行排序会更快。如果没有找到,则寻找长度为 N-1 的所有可能性,依此类推,直到找到。

标签: algorithm dynamic-programming greedy


【解决方案1】:

观察:如果你能得到一个能被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 的两个最小值,因为它是我们从这些存储桶中实际使用的唯一数字。

示例:

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"

【讨论】:

  • 我没有完全理解你的 O(n^2) 方法。您说要首先检查所有可能性以删除 1 个数字。没关系 。但在那之后呢?检查对如何给我答案?
  • @user1599964:您最多需要删除 2 个数字,如果您无法通过删除 3 个数字来获得可被 3 整除的数字 - 您根本无法获得。
  • @user1599964:使用上述观察 - 您可以获得O(n) 解决方案。我在编辑中添加了它。
  • 太棒了!简单高效!谢谢 !你和史蒂夫的答案是一样的......再次感谢!
  • 两点:可以在O(n)时间内完成,最多需要删除一个点(极端情况除外)。我的答案见下文。
【解决方案2】:

贪婪的选择绝对行不通:考虑集合{5, 2, 1}。你应该先删除1,但你应该删除2

我认为您应该计算出数组模 3 的总和,即 0(您已完成)或 1 或 2。然后您要删除总和模 3 为 1 的最小子集或 2.

我认为这相当简单,因此不需要动态编程。如果可能,通过删除一个具有该模数的数字来做到这一点,否则通过删除两个具有另一个模数的数字来做到这一点。一旦你知道要删除多少,请选择尽可能小的。您永远不需要删除三个数字。

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

综合起来,我可能会:

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

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

【讨论】:

  • 太棒了!你的和阿米特的解决方案是相同的。感谢伟大而简单的算法!
  • 是的,我正在写我的,而阿米特正在编辑他的。唯一的区别是他按模数分成三个桶,而我是数学家,所以我不能数到 3,我只是把它们都放在一个数组中;-)
【解决方案3】:

您对此有何看法:

首先按值对数组元素进行排序

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 种解决方案都相同.. 简单高效!
【解决方案4】:

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

Trivial:选择所有能被 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)

【讨论】:

    【解决方案5】:

    没有必要对数据进行排序,因为只有十个不同的值。 如果给出 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 等来创建解决方案。

    (对 n 位进行排序需要 O (n log n)。当然,除非您通过计算每个数字出现的频率并根据这些数字生成排序结果来进行排序)。

    【讨论】:

      【解决方案6】:

      Amit 的回答少了一点。

      如果 bucket1 不是空的,但它有一个巨大的值,比如说 79 和 97,b2 也不是空的,它的 2 个最小值是,比如 2 和 5。那么在这种情况下,当所有数字都是1,我们应该选择从bucket 2中删除2和5而不是bucket 1中的最小值,以获得最大的连接数。

      测试用例:8 2 3 5 78 79

      如果我们按照 Amits 和 Steve 建议的方法,最大的数是 878532,而这个数组中可能被 3 整除的最大数是 879783

      解决方案是将相应存储桶的最小最小值与另一个存储桶的最小值的串联进行比较,并消除较小的那个。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-10
        • 2022-11-21
        • 1970-01-01
        • 1970-01-01
        • 2018-09-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多