![](/img/trans.png)
[英]Find all pairs of elements from an array whose sum is equal to given number by hashmap in java
[英]An algorithm thats gives all possible distinct arrays whose positive integer elements sum to a given number
對於任何輸入的正整數,給出可以求和的所有可能的正非零整數數組的算法。
例如,輸入4將返回(1,1,1,1),(1,1,2),(1,2,1),(2,1,1),(1,3),(3,1), (2,2),(4)
不是功課,而是“研究”。 我只是迷路了。
擅長組合數學的人可能會知道這一點。
這是一些想法。
如果我沒記錯的話,數組的數目是2
N-1
,並且數組映射到位模式,編碼從0
到2
N-1
-1
整數,如下所示:
我將舉例說明N = 4
第一個數組是全1。 想象一下位模式中的每個位對應於兩個數組單元之間的邊界
1 1 1 1 <- array elements
| | | <- sections
0 0 0 <- bit pattern
位模式中的每1表示合並兩個相鄰單元
1 (1+1) 1 <- array elements (1 2 1)
| | | <- sections
0 1 0 <- bit pattern
1 (1+1+1) <- array elements (1 3)
| | | <- sections
0 1 1 <- bit pattern
(1+1) (1+1)<- array elements (2 2)
| | | <- sections
1 0 1 <- bit pattern
(1+1+1+1) <- array elements (4)
| | | <- sections
1 1 1 <- bit pattern
要枚舉所有數組,您可以生成0
到2
N-1
-1
整數,並且對於獲得的每個位模式,都生成相應的數組。 將整數轉換為零和長度為N-1
的字符串可能會有所幫助。 您可以按照以下方式解碼模式:
第一個單元格最初包含1
。 從左到右遍歷該模式,對於每個位,如果為1
,則向當前單元格添加1
;如果為0
,則創建包含1
新單元格。
N = 8
的模式1 1 0 0 1 0 1
將被解碼為數組
(3 1 2 2)
這是一些沒有參數驗證和從右到左處理模式的C ++代碼。 它只改變生成的數組的順序,並且更易於編寫代碼。
std::vector<std::vector<int> > generateArrays(unsigned int N)
{
//validate the argument before processing
// N > 0 and N <= numeric_limits<unsigned int>::digits
unsigned int numOfArrays = (1U << (N-1));
std::vector<std::vector<int> > result(numOfArrays);
for(unsigned int i = 0; i < numOfArrays; ++i)
{
result[i].push_back(1);
unsigned int mask = 1U;
while(mask < numOfArrays)
{
if((i & mask) != 0)
{
result[i].back()++;
}
else
{
result[i].push_back(1);
}
mask <<= 1;
}
}
return result;
}
遞歸! 第一個條目(稱為a [0])可以是從1到N的任何整數。然后,您只需要找到加在一起N-a [0]的所有不同的正非零整數數組。
遞歸方法
# Pseudo code, not any real language
function all_arrays_summing_to(int N) {
array_of_arrays All_solutions = ();
if (N == 1) return { [[1]] }; # This is array of one array containing 1 element with value 1
for each number x in (1 .. N-1) {
array_of_arrays AA = all_arrays_summing_to(N - x);
for each array A in (AA) {
push x onto array A;
Add A to All_solutions;
}
}
return All_solutions;
}
也許這不是最優雅的解決方案,因為我使用“ Distinct”來過濾出重復的結果,但這是C#中的一種方法。
一般的想法是將數字分成1的數組,然后將每個節點像樹一樣並排組合在一起,然后選擇不同的組合。 我像這樣描繪它:
[1,1,1]
/ \
[2,1] [1,2]
\ /
[3]
class Program
{
static void Main(string[] args)
{
Console.Write("Enter an integer value: ");
int num = int.Parse(Console.ReadLine());
var y = new int[num];
for (int x = 0; x < num; x++)
y[x] = 1;
var results = Combine(y, num)
.Distinct(new ArrayComparer())
.OrderByDescending(r => r.Length)
.ToArray();
foreach (var result in results)
{
Console.Write('[');
for (int x = 0; x < result.Length; x++)
{
if (x > 0)
Console.Write(", ");
Console.Write(result[x]);
}
Console.WriteLine(']');
}
Console.ReadKey(true);
}
public class ArrayComparer : IEqualityComparer<int[]>
{
bool IEqualityComparer<int[]>.Equals(int[] x, int[] y)
{
if (x.Length == y.Length)
{
for (int z = 0; z < x.Length; z++)
if (x[z] != y[z])
return false;
return true;
}
return false;
}
int IEqualityComparer<int[]>.GetHashCode(int[] obj)
{
return 0;
}
}
public static IEnumerable<int[]> Combine(int[] values, int num)
{
int val = 0;
for (int x = 0; x < values.Length; x++)
val += values[x];
if (val == num)
{
yield return values;
if (values.Length - 1 > 0)
{
for (int x = 0; x < values.Length; x++)
{
int[] combined = new int[values.Length - 1];
for (int y = 0; y < x; y++)
combined[y] = values[x];
if (values.Length > x + 1)
combined[x] = values[x] + values[x + 1];
for (int y = x + 2; y < values.Length; y++)
combined[y - 1] = values[y];
foreach (var result in Combine(combined, num))
yield return result;
}
}
}
}
}
輸出:
Enter an integer value: 4
[1, 1, 1, 1]
[2, 1, 1]
[1, 2, 1]
[1, 1, 2]
[3, 1]
[2, 2]
[1, 3]
[4]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.