2017-07-23 44 views
2

給定一個正整數n發現,所有組正整數的那筆到n找到所有組合之和爲數字

so 4 would be 
1 1 1 1 
2 1 1 
3 1 
2 2 

我認爲這是產生正確的數字,但我無法弄清楚如何打包結果。

public static IEnumerable<List<int>> BreakMeDown(int n) 
{ 
    for (int i = 1, j = n - 1; i <= j; i++, j--) 
    { 
     List<int> breakMeDown = new List<int>(); 
     breakMeDown.Add(i); 
     breakMeDown.Add(j); 
     yield return breakMeDown; 
     //Debug.WriteLine($"{i} {j}"); 
     foreach (List<int> li in BreakMeDown(i)) 
      yield return li; 
     foreach (List<int> li in BreakMeDown(j)) 
      yield return li;        
    } 
} 

// test 
foreach (List<int> li in BreakMeDown(7)) 
    Debug.WriteLine(string.Join(", ", li)); 
+1

其實是問題,「找到所有n對和n的正整數對**」?據我所知,你的算法總是產生長度爲2的列表,但許多數字可以表示爲3,4等加數的總和。 –

+0

@AsadSaeeduddin它一次評估一對,但遞歸它一直打破它,以產生所有。它只是不知道如何打包/分組。它只查看輸出的總和爲7,但總和爲7。如果你註釋掉遞歸,你可以得到這些對。 – Paparazzi

+0

我想也許我把j,j的每個故障與i的每個故障以及i和j的故障組的笛卡爾積連接起來。這應該涵蓋所有情況 –

回答

1

這裏,我們去:

static void Main(string[] args) 
{ 
    foreach (var li in BreakMeDown(7)) 
     Console.WriteLine(string.Join(", ", li)); 
} 

public static IEnumerable<IReadOnlyCollection<int>> BreakMeDown(int n) 
{ 
    for (int i = 1, j = n - 1; i <= j; i++, j--) 
    { 
     foreach (var li in BreakMeDown(j).Select(bd => bd.Concat(new[] {i}).ToList())) 
      yield return li; 
     foreach (var li in BreakMeDown(i).Select(bd => bd.Concat(new[] {j}).ToList())) 
      yield return li; 
     yield return new[] {i, j}; 
    } 
} 

編輯:

好了,根據你想刪除重複產生的序列的註釋。在這種情況下,要使用的正確數據結構是一個字典映射整數與出現次數。例如。 { 1: 5 }表示5的可能分解,其中數字1重複5次。

下面是代碼(我承擔了MoreLinq和Json.NET的依賴,因爲我不想要實現DistinctBy和對的IEqualityComparer詞典,但如果你願意,你可以做這些你自己):

static void Main(string[] args) 
    { 
     foreach (var li in BreakMeDown(5).DistinctBy(JsonConvert.SerializeObject)) 
      Console.WriteLine(string.Join(", ", li)); 
    } 

    static IImmutableDictionary<int, int> Increment(this IImmutableDictionary<int, int> dict, int i) 
    { 
     return dict.SetItem(i, dict.TryGetValue(i, out int iCount) ? iCount + 1 : 1); 
    } 

    public static IEnumerable<IImmutableDictionary<int, int>> BreakMeDown(int n) 
    { 
     for (int i = 1, j = n - 1; i <= j; i++, j--) 
     { 
      var iAndJ = ImmutableSortedDictionary.Create<int, int>().Increment(i).Increment(j); 
      var bdJ = BreakMeDown(j).Select(bd => bd.Increment(i)); 
      var bdI = BreakMeDown(i).Select(bd => bd.Increment(j)); 

      var list = bdI.Concat(bdJ).Concat(new[] { iAndJ }); 
      foreach (var li in list) 
      { 
       yield return li; 
      } 
     } 
    } 
+0

請downvoter請解釋是什麼問題?答案正確地計算了總和到所需數量的所有序列。 –

+0

這太棒了。我投了票,現在還沒有倒票。我的意思不是貪婪,而是產生重複。 {1,2,1,1,1,1} = {1,1,1,1,1,1}你知道如何解決這個問題嗎? – Paparazzi

+0

@Paparazzi是的,算法的工作方式'i'和'j'的細分可能會產生重複。解決方法非常簡單,只需將兩個分解結果連接起來,然後映射它們來生成集合而不是'IReadOnlyCollection's,然後使用'Distinct'。我會設置並更新答案。 –

1

我認爲你正在尋找這個(不能測試它,所以我現在不是100%的正預期它會工作):

public static IEnumerable<List<int>> BreakMeDown(int n) 
{ 
    for (int i = 1, j = n - 1; i <= j; i++, j--) 
    { 
     List<int> breakMeDown = new List<int>(); 
     breakMeDown.Add(i); 
     breakMeDown.Add(j); 
     yield return breakMeDown; 

     foreach (List<int> li in BreakMeDown(i)) 
      yield return breakMeDown.Skip(1) 
            .Concat(li) 
            .ToList(); 

     if (i != j) 
     { 
      foreach (List<int> li in BreakMeDown(j)) 
       yield return breakMeDown.Take(1) 
             .Concat(li) 
             .ToList(); 
     } 
    } 
} 

當你創建遞歸故障,您需要連接的結果到已經建成的2個因素分解中,忽略了你被破壞的因素進一步下跌。

+0

還有一些重複例如1,1,2,1,1 – Paparazzi

+0

@Paparazzi嗯,確切的重複只應發生在雙方崩潰相同時,應該只發生在'i == j'(我承認我沒有想過它通過完全但它的聲音)...看到編輯,並試試看,讓我知道它是否有訣竅 – InBetween

+0

@Paparazzi對不起,忘了更新代碼。 – InBetween