如何在C++中生成字符串的无重复所有组合?
C++生成字符串无重复组合的实现方案
嘿,我来帮你搞定这个问题!你要的其实是保持原字符串字符顺序的所有非空子集——毕竟你提到的"重复"是像"12"和"21"这种打乱顺序的情况,只要我们严格遵循原字符串的字符顺序生成组合,就能从根源避免这类重复。
下面给你两种实现方式,递归和迭代都有,你可以按需选择:
一、递归实现(完美匹配示例输出顺序)
递归的思路其实就是模拟"选或不选当前字符"的决策树,调整递归顺序就能完美贴合你要的输出顺序:
#include <iostream> #include <vector> #include <string> // 递归核心函数:index是当前处理的字符索引,current是当前拼接的组合,result存最终结果 void generateCombinations(const std::string& s, int index, std::string current, std::vector<std::string>& result) { // 所有字符处理完毕,非空组合加入结果 if (index == s.size()) { if (!current.empty()) { result.push_back(current); } return; } // 优先选择当前字符,保证生成的组合顺序和示例一致(先处理以当前字符开头的所有组合) current.push_back(s[index]); generateCombinations(s, index + 1, current, result); // 回溯:去掉当前字符,处理不选它的情况 current.pop_back(); generateCombinations(s, index + 1, current, result); } int main() { std::string input = "123"; std::vector<std::string> combinations; generateCombinations(input, 0, "", combinations); // 按示例格式输出 for (size_t i = 0; i < combinations.size(); ++i) { if (i != 0) std::cout << ","; std::cout << combinations[i]; } std::cout << std::endl; // 输出:1,12,123,13,2,23,3 return 0; }
递归思路解释:
- 每一步处理到第
index个字符时,先把它加入当前组合,递归处理后面的字符——这样会生成所有以当前字符开头的组合(比如处理"1"时,会生成"1"、"12"、"123",然后回溯去掉"2"生成"13")。 - 回溯后再处理"不选当前字符"的情况,继续递归后面的字符——比如去掉"1"后,处理"2"生成"2"、"23",再去掉"2"处理"3"生成"3"。
- 这种顺序完全贴合你给出的示例输出,而且因为严格遵循原字符串的字符顺序,绝对不会出现"21"、"213"这类打乱顺序的重复组合。
二、迭代实现(无递归开销,灵活调整顺序)
如果你不想用递归,也可以用迭代的方式生成所有组合,只是默认顺序和示例不同,但内容完全正确:
#include <iostream> #include <vector> #include <string> std::vector<std::string> generateCombinationsIterative(const std::string& s) { std::vector<std::string> result; // 初始加入空组合,作为扩展基础 result.push_back(""); // 遍历每个字符,用现有组合拼接生成新组合 for (char c : s) { size_t currentSize = result.size(); // 对每个已有的组合,拼接当前字符生成新组合并加入结果 for (size_t i = 0; i < currentSize; ++i) { result.push_back(result[i] + c); } } // 移除初始的空组合,得到所有非空组合 result.erase(result.begin()); return result; } int main() { std::string input = "123"; std::vector<std::string> combinations = generateCombinationsIterative(input); // 输出结果(默认顺序:1,2,12,3,13,23,123) for (size_t i = 0; i < combinations.size(); ++i) { if (i != 0) std::cout << ","; std::cout << combinations[i]; } std::cout << std::endl; return 0; }
迭代思路解释:
- 从空组合开始,每加入一个新字符,就把它和现有所有组合拼接,生成新的组合。比如处理"1"时,生成"1";处理"2"时,用""+"2"生成"2","1"+"2"生成"12";处理"3"时,生成"3"、"13"、"23"、"123",最终得到所有组合。
关于你遇到的重复问题
你之前说自己的实现有重复,大概率是因为没有限制字符的相对顺序,比如允许了打乱原字符串顺序的排列(比如生成了"21")。而我们的两种方法都严格保证组合中的字符顺序和原字符串一致,从根源避免了这类重复。你提到的"结果树"其实就是递归的核心思路——每个节点对应一个字符的"选/不选"决策,遍历这棵树就能得到所有合法组合。
内容的提问来源于stack exchange,提问作者Nick Law
相关产品推荐
相关产品推荐

