[LeetCode] 1286. Iterator for Combination 字母組合迭代器
Design theCombinationIterator
class:
CombinationIterator(string characters, int combinationLength)
Initializes the object with a stringcharacters
ofsorted distinctlowercase English letters and a numbercombinationLength
as arguments.next()
Returns the next combination of lengthcombinationLength
inlexicographical order.hasNext()
Returnstrue
if and only if there exists a next combination.
Example 1:
Input ["CombinationIterator", "next", "hasNext", "next", "hasNext", "next", "hasNext"] [["abc", 2], [], [], [], [], [], []] Output [null, "ab", true, "ac", true, "bc", false] Explanation CombinationIterator itr = new CombinationIterator("abc", 2); itr.next(); // return "ab" itr.hasNext(); // return True itr.next(); // return "ac" itr.hasNext(); // return True itr.next(); // return "bc" itr.hasNext(); // return False
Constraints:
1 <= combinationLength <= characters.length <= 15
- All the characters of
characters
areunique. - At most
104
calls will be made tonext
andhasNext
. - It is guaranteed that all calls of the function
next
are valid.
這道題讓設計一個 CombinationIterator 類,初始化時給一個有序的字串,然後一個組合的長度,有兩個成員函式,一個是 next() 函式,是返回下一個按字母順序,且是給定長度的組合,另一個 hasNext() 函式用來判斷是否還存在下一個組合。給的例子可以很好的幫助我們理解題意,比如給的字串是 "abc",返回組合的長度是2的話,則就是按照字母順序來返回組合,"ab", "ac", "bc"。其實本質就是找出給定長度的所有組合,就拿給的例子 "abc" 來說吧,找出兩個字母的組合,就是在三個字母中任意選兩個,如果用1表示選擇該字母,0表示不選的話,就有如下種情況:
a b c
0 0 0 -> ""
0 0 1 -> c
0 1 0 -> b
0 1 1 -> bc
1 0 0 -> a
1 0 1 -> ac
1 1 0 -> ab
1 1 1 -> abc
而每種情況正好對應一個二進位制數,有三個字母的話,子集總個數為 2^3 = 8 個,每一種可以用一個二進位制 mask 來表示,目標就是找出長度為2的組合。至於字母順序不用太擔心,將所有找出的組合放到一個 TreeSet 中,利用其自動排序的功能就行了。所以 mask 從1遍歷到 2^n(這裡的n為3),然後遍歷給定字串的長度,去看 mask 對應位上是1還是0,為1的話就將對應位的字母加到t中,最後看t的長度是多少,若是2的話,就加到 TreeSet 中。等將所有的長度為2的組合就找出來加到 TreeSet 中了之後,next 和 hasNext 函式就非常好實現了,用一個 iterator 就行了,next 就是看迭代器是否到末尾了,是的話返回空,否則返回當前指向到元素,並且迭代器後移一位。hasNext 就看迭代器是否到末尾了就行了,參見程式碼如下:
解法一:
class CombinationIterator {
public:
CombinationIterator(string characters, int combinationLength) {
st = generateAll(characters, combinationLength);
cur = begin(st);
}
string next() {
return cur == end(st) ? "" : *cur++;
}
bool hasNext() {
return cur != end(st);
}
private:
set<string> st;
set<string>::iterator cur;
set<string> generateAll(string str, int len) {
set<string> res;
int n = 1 << str.size();
for (int mask = 1; mask < n; ++mask) {
string t = "";
for (int i = 0; i < str.size(); ++i) {
if (mask & (1 << i)) t += str[i];
}
if (t.size() == len) res.insert(t);
}
return res;
}
};
我們也可以用迭代的方法來找出所有的組合,寫法能稍微簡潔一些,遞迴函式 generateAll 需要多加兩個引數,start 和 res,分別是當前遍歷到的位置,而當前組成的字串。在遞迴函式中,若 len 為0了,則表示找到所求長度的組合,將其加入 TreeSet 中,否則就從 start 遍歷到 n-len,然後呼叫遞迴函式,此時代入 len-1,i+1,和 res+str[i] 作為引數即可,參見程式碼如下:
解法二:
class CombinationIterator {
public:
CombinationIterator(string characters, int combinationLength) {
generateAll(characters, combinationLength, 0, "");
cur = begin(st);
}
string next() {
return cur == end(st) ? "" : *cur++;
}
bool hasNext() {
return cur != end(st);
}
private:
set<string> st;
set<string>::iterator cur;
void generateAll(string str, int len, int start, string res) {
if (len == 0) {
st.insert(res);
return;
}
for (int i = start; i <= (int)str.size() - len; ++i) {
generateAll(str, len - 1, i + 1, res + str[i]);
}
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/1286
參考資料:
https://leetcode.com/problems/iterator-for-combination/
https://leetcode.com/problems/iterator-for-combination/discuss/451322/(JAVA)-Generate-Combinations
LeetCode All in One 題目講解彙總(持續更新中...)
微信打賞 |
Venmo 打賞 |