数组中等于 N 的 K 个元素的总和

Posted

技术标签:

【中文标题】数组中等于 N 的 K 个元素的总和【英文标题】:Sum of K elements in array that equates to N 【发布时间】:2013-01-12 14:40:56 【问题描述】:

给定一个数组,比如 nums = 1,2,5,3,6,-1,-2,10,11,12,使用最大元素数(比如 maxNums=3) 找到总和(比如 sum =10)= K 的元素

所以如果要使用的 maxNums = 3 求和 = 10 答案是

    1  3  6    
    1  -1  10
    1  -2  11
    2  5  3
    2  -2  10
    5 6 -1
    -1  11
    -2  12
    10

我写了一个递归函数来完成这项工作。 如何在没有递归的情况下做到这一点? 和/或内存更少?

class Program

        static Int32[] nums =  1,2,5,3,6,-1,-2,10,11,12;
        static Int32 sum = 10;
        static Int32 maxNums = 3;


        static void Main(string[] args)
        

            Int32[] arr = new Int32[nums.Length];
            CurrentSum(0, 0, 0, arr);

            Console.ReadLine();
        

        public static void Print(Int32[] arr)
        
            for (Int32 i = 0; i < arr.Length; i++)
            
                if (arr[i] != 0)
                    Console.Write("  "   +arr[i]);
            
            Console.WriteLine();
        


        public static void CurrentSum(Int32 sumSoFar, Int32 numsUsed, Int32 startIndex, Int32[] selectedNums)
        
            if ( startIndex >= nums.Length  || numsUsed > maxNums)
            
                if (sumSoFar == sum && numsUsed <= maxNums)
                
                    Print(selectedNums);
                                    
                return;
            

                       **//Include the next number and check the sum**
                    selectedNums[startIndex] = nums[startIndex];
                    CurrentSum(sumSoFar + nums[startIndex], numsUsed+1, startIndex+1, selectedNums);

                    **//Dont include the next number**
                    selectedNums[startIndex] = 0;
                    CurrentSum(sumSoFar , numsUsed , startIndex + 1, selectedNums);
        
    

【问题讨论】:

问题不清楚,你使用的语言也不清楚 我使用 C# 作为语言 这是子集和问题;这是一个非常著名的问题。有大量关于如何解决它的文献,尽管重要的是要注意在其最一般的形式中它不能快速解决。(也就是说,有一个快速解决方案当且仅当 P= =NP,而且 P 几乎可以肯定不等于 NP。) 数组内元素的最小和最大可能值是多少? 您不关心运行时间而只想摆脱递归?在这种情况下,我会给你一个提示。考虑堆栈中存储的内容。将其拉出并放入数组中。观察你的递归不会比 maxNums 级别更深。 【参考方案1】:

你的功能看起来不错,但可能有点优化:

class Program

    static Int32[] nums =  1, 2, 5, 3, 6, -1, -2, 10, 11, 12 ;
    static Int32 sum = 10;
    static Int32 maxNums = 3;
    static Int32[] selectedNums = new Int32[maxNums];

    static void Main(string[] args)
    
        CurrentSum(0, 0, 0);
        Console.ReadLine();
    

    public static void Print(int count)
    
        for (Int32 i = 0; i < count; i++)
        
            Console.Write(" " + selectedNums[i]);
        
        Console.WriteLine();
    

    public static void CurrentSum(Int32 sumSoFar, Int32 numsUsed, Int32 startIndex)
    
        if (sumSoFar == sum && numsUsed <= maxNums)
        
            Print(numsUsed);
        

        if (numsUsed >= maxNums || startIndex >= nums.Length)
            return;

        for (int i = startIndex; i < nums.Length; i++)
        
            // Include i'th number
            selectedNums[numsUsed] = nums[i];
            CurrentSum(sumSoFar + nums[i], numsUsed + 1, i + 1);
        
    

我还修复了你的函数中的一个错误。 以下测试用例失败:

10, 2, -2
Sum = 10
K = 3

您的函数仅返回 10 而不是 10 and 10, 2, -2

【讨论】:

你已经接近了。你为什么不完全摆脱递归。显然你并没有真的将堆栈用于任何事情。 他需要更少的内存使用。在这个问题中没有使用深度递归,因为工作时间是 2^N。其中N max 可能是递归的深度,其实这并没有用到很多内存。通过使用 sumSoFar 和 numsUSed 作为全局变量,我提供的算法可能会有所改进。【参考方案2】:

还有 Haskell 解决方案...

import Data.List
listElements max_num k arr = 
  filter (\x -> sum x == k && length x == max_num) $ subsequences arr

*Main> listElements 3 10 [1,2,5,3,6,-1,-2,10,11,12] [[2,5,3],[1,3,6],[5,6,-1],[1,-1,10],[2,-2,10],[1,-2, 11]]

【讨论】:

以上是关于数组中等于 N 的 K 个元素的总和的主要内容,如果未能解决你的问题,请参考以下文章

计算组合的有效算法,数组的重复加起来等于给定的总和

数组中的两个不同数字,它们的和等于给定值

总和大于或等于 k ​​的最小子集

是否可以对数组中的每 3 个相邻元素求和,并使用向量指令使它们中的每一个都等于总和?

1001 数组中和等于K的数对

1001 数组中和等于K的数对