无重复数字的数组最大和

时间:2019-05-25 05:47:31

标签: algorithm dynamic-programming

我想找到可以从数字数组中获得的最大和。但是限制是没有两个数字可以有任何共同的数字。

示例:

  

输入:121,23,3,333,4

     

输出:458(121 + 333 + 4)

我整夜都在考虑解决方案,但是除了这个没办法:

  1. 考虑数组的所有子集
  2. 查找数字不重复的子集的总和
  3. 输出这些总和的最大值

但是由于数组元素的数量最多可以达到100,所以时间复杂度将为2 ^ 100。 还有其他方法吗?喜欢动态编程吗?

1 个答案:

答案 0 :(得分:10)

这可以通过在 O(n 2 d 中进行动态编程来解决,其中n是数组中元素的数量,而{{1} }是数字系统中的位数。在这种情况下,由于我们使用的是十进制数字系统d

想象一下,如果数字d = 10存在于数字中,那么是否将数字的位掩码设置为第i 位。

重复关系

  

dp(位掩码)= max(dp(位掩码^ mask(a [i]))+ a [i]对于所有i,其中   mask(a [i])是位掩码的子集

这个想法是试图包含一个数字,以便仅在该数字的位掩码是获得解决方案的位掩码的子集时才能获得最大值。然后要解决的子问题是找到未设置i位的位掩码的解决方案。

时间复杂度

动态编程重复中有 2 d 个状态。对于每个状态,都需要对数组进行交互以计算最大值。因此,动态存储编程解决方案的总体时间复杂度变为 O(n 2 d 。运行时复杂度还取决于 O(log 10 a i 函数的大小,但取决于数组内部元素的大小将其视为常量。

代码

这是一个C ++自顶向下的实现记录:

mask(a[i])

驱动程序代码:

int mask(int n) {
  int mask = 0;
  for (int i = 1; n/i; i*= 10) {
    int digit = n/i % 10;
    mask |= 1 << digit;
  }
  return mask;
}

int dp(int set, int memo[1<<10], const vector<int>& a) {
  if (set == 0) {
    return memo[set] = 0;
  }
  if (memo[set] != -1)
    return memo[set];

  int res = 0;
  for (auto num: a) {
    int bitmask = mask(num);
    if ((set | bitmask) == set)
      res = std::max(dp(set ^ mask(num), memo, a) + num, res);
  }
  return memo[set] = res;
}

Demo