你可以通過組合一個在像通過使用陣列來記錄每個內陣列的大小發條的時間,並且以跟蹤從每個陣列內使用的構件的計數器陣列迭代。這樣的方法的東西:
/**
* Produce a List<String> which contains every combination which can be
* made by taking one String from each inner String array within the
* provided two-dimensional String array.
* @param twoDimStringArray a two-dimensional String array which contains
* String arrays of variable length.
* @return a List which contains every String which can be formed by taking
* one String from each String array within the specified two-dimensional
* array.
*/
public static List<String> combinations(String[][] twoDimStringArray) {
// keep track of the size of each inner String array
int sizeArray[] = new int[twoDimStringArray.length];
// keep track of the index of each inner String array which will be used
// to make the next combination
int counterArray[] = new int[twoDimStringArray.length];
// Discover the size of each inner array and populate sizeArray.
// Also calculate the total number of combinations possible using the
// inner String array sizes.
int totalCombinationCount = 1;
for(int i = 0; i < twoDimStringArray.length; ++i) {
sizeArray[i] = twoDimStringArray[i].length;
totalCombinationCount *= twoDimStringArray[i].length;
}
// Store the combinations in a List of String objects
List<String> combinationList = new ArrayList<String>(totalCombinationCount);
StringBuilder sb; // more efficient than String for concatenation
for (int countdown = totalCombinationCount; countdown > 0; --countdown) {
// Run through the inner arrays, grabbing the member from the index
// specified by the counterArray for each inner array, and build a
// combination string.
sb = new StringBuilder();
for(int i = 0; i < twoDimStringArray.length; ++i) {
sb.append(twoDimStringArray[i][counterArray[i]]);
}
combinationList.add(sb.toString()); // add new combination to list
// Now we need to increment the counterArray so that the next
// combination is taken on the next iteration of this loop.
for(int incIndex = twoDimStringArray.length - 1; incIndex >= 0; --incIndex) {
if(counterArray[incIndex] + 1 < sizeArray[incIndex]) {
++counterArray[incIndex];
// None of the indices of higher significance need to be
// incremented, so jump out of this for loop at this point.
break;
}
// The index at this position is at its max value, so zero it
// and continue this loop to increment the index which is more
// significant than this one.
counterArray[incIndex] = 0;
}
}
return combinationList;
}
如何。如果你想象中的計數器陣列是像一個數字時鐘,然後讀取第一個字符串組合的方法工作
看到在全零的計數器陣列,使得第一串是通過取每個內部數組的零元素(第一個成員)。
要獲得下一個組合,計數器陣列會加1。所以最不重要的計數器指數增加1。如果這導致它的值等於它所表示的內部數組的長度,那麼索引被歸零,並且下一個更重要的索引被增加。一個單獨的大小數組存儲每個內部數組的長度,以便計數器數組循環知道索引何時達到其最大值。
例如,如果該尺寸數組是:
[3][3][2][1]
和計數器陣列是在:
[0][2][1][0]
然後增量將使至少顯著(最右側)指數等於1,這是它的最大值。因此,該指數被歸零,下一個更重要的指標(右起第二個)增加到2.但是這也是該指數的最大值,所以它被歸零,我們轉向下一個具有更大重要性的指標。這會增加到三,這是它的最大值,所以它被歸零,我們移動到最重要的(最左邊的)指數。這樣遞增的計數器陣列變成被增大到1,它是小於其最大:
[1][0][0][0]
這意味着下一個字符串組合是通過取第一內陣列的第二構件製成,並且所述第一構件接下來的三個內部陣列。
可怕的警告和注意事項
我剛纔在40分鐘左右寫到這,和它的半一個早上,這意味着,即使它似乎做的是需要什麼,有很可能的錯誤或可以被優化的代碼位。因此,如果其性能至關重要,請務必對其進行徹底的測試。
請注意,它返回一個List而不是一個String數組,因爲我認爲Java Collections在大多數情況下比使用數組更好。另外,如果你需要一個沒有重複的結果集,你可以簡單地將List更改爲一個Set,它會自動刪除重複項,併爲你留下一個唯一的集合。
如果您確實需要將結果作爲字符串數組,請不要忘記您可以使用List<String>.toArray(String[])
方法將返回的List簡單地轉換爲您所需的。
老兄,你的代碼工作,非常感謝。但是我只是繼續看着它,不知道爲什麼,你能提供一些你使用的算法的一些解釋 - 基本步驟和關於每一步的一些細節,我只是沒有得到它背後的魔力。 – lekroif 2013-04-08 01:34:19
@lekroif從粗略的一瞥中,它看起來像計算你可以做的組合的總數,然後初始化一個計數器陣列,每個組合的數組一個 - 一端的計數器循環,每次它循環它遞增下一個,如果循環下一個遞增,依此類推。用杯子想一下公文包鎖。 – Patashu 2013-04-08 02:07:11
@lekroif我在代碼中添加了一個大塊,它貫穿了方法的工作方式。 Patashu是正確的:它就像一個數字刻度盤一樣,每次產生下一個組合的座標,直到它已經穿過每個可能的座標組合。我還修改了上面的代碼,以刪除我發佈的第一個版本中不必要的調零循環。 – Bobulous 2013-04-08 18:25:36