簡體   English   中英

找到 3 個和給定數字相加的數字

[英]Find 3 numbers that are sum up to a given number

我需要創建一個遞歸方法,它以一個數字作為輸入(范圍從 3 到 30,不包括),並找到添加三個自然數(范圍從 1 到 10,包括)的所有組合,以便它們等於這個數字。

例如,如果輸入是5 ,我需要找到所有6組合: "1+1+3""1+2+2""1+3+1""2+1+2" , "2+2+1""3+1+1"

該方法應該打印選項,並返回選項的數量。 到目前為止,這是我的代碼:

public static int solutions(int num)
{
    if(num < 3 || num >30)
        return 0;
    return solutions(1,1,1, num);
}

private static int solutions(int x1, int x2, int x3, int num)
{
    if(x1 > 10 || x2 > 10 || x3 > 10)
        return 0;
    if (x1+x2+x3 != num)
    {
        return  solutions(x1 + 1, x2, x3, num)+
                solutions(x1, x2 + 1, x3, num)+
                solutions(x1, x2, x3 + 1, num);
    }
    else 
    {
        System.out.println(x1 + "+" + x2 +"+" + x3);
        return 1;
    }
}

這段代碼給了我太多答案(都是正確但多余的),例如 5 它給了我 9 個答案而不是 6 個。

您的算法的問題在於它將具有重復的遞歸路徑。 一個直接的解決方案是調整算法以使用一個集合來避免重復:

public static void solutions(int x1, int x2, int x3, int num, 
                             Set<String> combinations){
       if (x1 + x2 + x3 == num) {
            combinations.add(x1 + "+" + x2 +"+" + x3);
        } else if ( x1 <= num - 2 && x2 <= num - 2 && x3 <= num - 2
                   && x1 <= 10 && x2 <= 10 && x3 <= 10
                   && x1 + x2 + x3 < num) {
                  if(x1 < 10) solutions(x1 + 1, x2, x3, num, combinations);
                  if(x2 < 10) solutions(x1, x2 + 1, x3, num, combinations);
                  if(x3 < 10) solutions(x1, x2, x3 + 1, num, combinations);
       }
}

但是,由於遞歸調用的數量,這種解決方案有點慢。 例如:

num = 3 -> count = 1 duplicates found 1 Time taken 0.04(s)
num = 4 -> count = 3 duplicates found 3 Time taken 0.0(s)
num = 5 -> count = 6 duplicates found 9 Time taken 0.0(s)
...
num = 10 -> count = 36 duplicates found 2187 Time taken 0.004(s)
...
num = 20 -> count = 63 duplicates found 118569594 Time taken 5.739(s)
...

查看找到的重復項的數量,可以看到有相當數量的無用遞歸調用會導致開銷。 盡管如此,我們可以進一步限制遞歸調用的數量。 我們只需要調用:

solutions(x1, x2 + 1, x3, num, combinations);

如果(x1 <= x2)。

此外,不需要對x3進行遞歸調用,可以使用公式x3 = num - x2 - x1推斷其值。 所以優化后的版本如下所示:

public static void solutions(int x1, int x2, int x3, int num, Set<String> combinations){
    if(x1 <= 10 && x2 <= 10 && (num - x2 - x1) <= 10) {
        combinations.add(x1 + "+" + x2 + "+" + (num - x2 - x1));
    }
    if ( x1 <= num - 2 && x2 <= num - 2 && x3 <= num - 2 && x1 + x2 + x3 < num) {
        if(x1 < 10) solutions(x1 + 1, x2, x3, num, combinations);
        if(x2 < 10 && x1 <= x2) solutions(x1, x2 + 1, x3, num, combinations);
    }
}

結果:

num = 3 -> count = 1 duplicates found 0 Time taken 0.045(s)
num = 4 -> count = 3 duplicates found 0 Time taken 0.0(s)
num = 5 -> count = 6 duplicates found 0 Time taken 0.0(s)
...
num = 10 -> count = 36 duplicates found 65 Time taken 0.001(s)
... 
num = 20 -> count = 63 duplicates found 21670 Time taken 0.018(s)
....

對於num = 20 ,遞歸調用減少了大約5471x 在我的機器上,它從 5.739 秒減少到了 0.018 秒。 如果找到更多可以限制遞歸調用次數的表達式,算法會快得多。 理想情況下,找到將重復數量減少到0的表達式,從而消除對集合的需求。

一個更好的解決方案:

在對該主題進行了一些研究之后,我推導出了一個算法(基於此處提供的解決方案),它使用上述表達式將重復的數量減少到 0,從而消除了使用set的需要。 基本上,我重新排列和更改了先前解決方案的表達式及其邏輯,並應用了刪除x3的遞歸調用的優化,以減少遞歸調用的總數,. 即從167792007的總體遞歸調用(與帶有set的優化版本的328991相比)。 代碼如下所示:

private static int solutions2(int x1, int x2, int x3, int num){
        int count = 0;
        if (x2 < Math.min(10, num - x1)) count = solutions2(x1, x2 + 1, 1,num);
        else if (x1 < Math.min(10, num)) count = solutions2(x1 + 1, 1, 1, num);
        if(x1 <= 10 && x2 <= 10) {
            int x3_tmp = num - x2 - x1;
            if(0 < x3_tmp && x3_tmp <= 10) {
                System.out.println(x1 + "+" + x2 +"+" + x3);
                return 1 + count;
            }
        }
        return count;
}

一個運行的例子:

class Example {

    private static int solutions(int x1, int x2, int num){
        int count = 0;
        if (x2 < Math.min(10, num - x1)) count = solutions(x1, x2 + 1, num);
        else if (x1 < Math.min(10, num)) count = solutions(x1 + 1, 1, num);
        if(x1 <= 10 && x2 <= 10) {
            int x3_tmp = num - x2 - x1;
            if(0 < x3_tmp && x3_tmp <= 10) {
                System.out.println(x1 + "+" + x2 + "+" + x3_tmp);
                return 1 + count;
            }
        }
        return count;
    }

    public static int solutions(int num){
        return (num < 3 || num > 30) ? 0 : solutions(1,1, num);
    }
    public static void main(String[] args){
            int count = solutions(5);
            System.out.println("Count = " +count);
    }
}

你會得到 output:

3+1+1
2+2+1
2+1+2
1+3+1
1+2+2
1+1+3
Count : 6

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM