【问题标题】:Every sum possibilities of elements元素的每个和可能性
【发布时间】:2018-06-05 09:19:32
【问题描述】:

从给定的数组(称为 numbers[])中,我想要另一个数组(results[]),其中包含第一个数组元素之间的所有求和可能性。

例如,如果我有 numbers[] = {1,3,5},results[] 将是 {1,3,5,4,8,6,9,0}。 有 2^n 种可能性。 一个数字是否出现两次并不重要,因为 results[] 将是 set

我是为配对或三胞胎的总和做的,这很容易。但是我不明白当我们将 0、1、2 或 n 个数字相加时它是如何工作的。

这就是我为配对所做的:

std::unordered_set<int> pairPossibilities(std::vector<int> &numbers) {
    std::unordered_set<int> results;
    for(int i=0;i<numbers.size()-1;i++) {
        for(int j=i+1;j<numbers.size();j++) {
            results.insert(numbers.at(i)+numbers.at(j));
        }
    }
    return results;
}

另外,假设 numbers[] 已排序,是否有可能在填充时对 results[] 进行排序?

谢谢!

【问题讨论】:

  • 探索std::partial_sumstd::accumulate

标签: c++ algorithm math


【解决方案1】:

这可以通过Dynamic Programming (DP) in O(n*W) where W = sum{numbers} 来完成。

这与Subset Sum Problem的解决方案基本相同,利用了问题具有最优子结构这一事实。

DP[i, 0] = true
DP[-1, w] = false          w != 0
DP[i, w] = DP[i-1, w] OR DP[i-1, w - numbers[i]]

首先按照上面的解决方案找到DP[n, sum{numbers}]

结果,你会得到:

DP[n , w] = true 当且仅当w 可以从numbers 构造出来

【讨论】:

    【解决方案2】:

    从动态编程答案开始,您可以使用递归解决方案,然后使用记忆化来缓存结果,与 Amit 的自下而上相比,自上而下的方法。

    vector<int> subsetSum(vector<int>& nums)
    {
        vector<int> ans;
        generateSubsetSum(ans,0,nums,0);
        return ans;
    }
    
    void generateSubsetSum(vector<int>& ans, int sum, vector<int>& nums, int i)
    {
        if(i == nums.size() )
        {
            ans.push_back(sum);
            return;
        }
    
        generateSubsetSum(ans,sum + nums[i],nums,i + 1);
        generateSubsetSum(ans,sum,nums,i + 1);
    }
    

    Result is : {9 4 6 1 8 3 5 0} 为集合{1,3,5}

    这只是在第一个索引i 处选择第一个数字,将其添加到sum 并递归。一旦它返回,第二个分支 sum 就会出现,但没有添加 nums[i]。要记住这一点,您将有一个缓存来将sum 存储在i

    【讨论】:

      【解决方案3】:

      我会做这样的事情(看起来更容易)[我想把它放在评论中,但不能一次写移位和删除元素 - 你可能需要一个链表]

      1 3 5
      3 5
      -----
      4 8
      
      
      1 3 5
      5
      -----
      6
      
      1 3 5
      3 5
      5
      ------
      9
      

      在最后添加0

      解决此问题的另一种方法是创建元素向量的子集数组,然后对每个数组的向量数据求和。 例如 1 3 5 = {1, 3} + {1,5} + {3,5} + {1,3,5} 删除单个元素集后。

      请记住,说起来容易做起来难。实现算法中的一个小错误将需要大量的调试时间才能发现。 =]]

      【讨论】:

        【解决方案4】:

        还必须有二进制印章版本。这个有点笨拙,依靠您提到的那组答案来过滤重复的结果:

        Split the list into 2,  
        and generate the list of sums for each half 
          by recursion:
            the minimum state is either 
              2 entries, with 1 result, 
              or 3 entries with 3 results
              alternatively, take it down to 1 entry with 0 results, if you insist
        Then combine the 2 halves:
          All the returned entries from both halves are legitimate results
          There are 4 additional result sets to add to the output result by combining:
            The first half inputs vs the second half inputs
            The first half outputs vs the second half inputs
            The first half inputs vs the second half outputs
            The first half outputs vs the second half outputs
        

        请注意,两半的输出可能有一些共同的元素,但对于这些组合,它们应该分开处理。
        如果输入是合法的最终结果,则可以从每个递归的返回输出中清除输入。如果是,则可以在顶层阶段重新添加,也可以由底层阶段返回,并且在合并中不再考虑。

        您可以使用位域而不是集合来过滤掉重复项。有相当有效的方法可以逐步遍历位域以查找所有设置位。位域的最大大小是所有输入的总和。

        这里没有智能,但有很多机会在递归和合并步骤中进行并行处理。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-07-18
          • 2011-11-20
          • 2012-07-24
          • 1970-01-01
          • 2018-03-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多