字母组合
一.题目
二.歧义
这题目文字描述和样例没有讲清楚:
1.是否要做输入的数字校验,因为有可能输入超过10的数字
2.输入的字符和数字之间一定用空格分隔,还是可以不分割。
三.解题思路
这道题剔除一些无关简要的代码,可以采用暴力排列组合,也可以采用动态规划。由于此题难度其实不大, 也不涉及背包问题,就采用了暴力的排列组合。
四.代码
1.先上主函数 。
- 先初始化加载关联字母。
- 输入cin
- 因为题目没有讲清楚输入是否一定采用空格分隔,这里做了切分和内部转换为数字
- 通过用户输入的数字获取哪些字母集合要进行排列
- 进行排列
- 剔除屏蔽的字符
- 输出结果
void main()
{
InitDictionary();
std::string numString;
std::string ingnoreString;
std::getline(std::cin ,numString);
std::getline(std::cin, ingnoreString);
std::cout << std::endl;
std::string space = " ";
//分割字符串
std::vector<int> nums = SplitStringToDigit(numString, space);
bool isContainSameDigit = IsContainSameDigit(nums);
if (isContainSameDigit)
return;
std::vector<char> ignore = SplitString(ingnoreString, space);
//做完校验,获取到用户输入的信息之后 就可以开始 排列组合 剔除掉受影响的组合即可。 这里可以用排列组合,也可以用动态规划的思维来解决问题
std::vector<std::vector<char>> sources = GetDictionary(nums);
std::vector<std::vector<char>> result=GetPermutation(sources, ignore);
for (auto& vect : result)
{
std::string str;
for (char c : vect)
{
str += c;
}
std::cout << str << std::endl;
}
}
2.初始化关联字母
std::unordered_map<int, std::vector<char>> dictionary;
void InitDictionary()
{
std::vector<char> v0 = { 'a','b','c' };
std::vector<char> v1 = { 'd','e','f' };
std::vector<char> v2 = { 'g','h','i' };
std::vector<char> v3 = { 'j','k','l' };
std::vector<char> v4 = { 'm','n','o' };
std::vector<char> v5 = { 'p','q','r' };
std::vector<char> v6 = { 's','t' };
std::vector<char> v7 = { 'u','v' };
std::vector<char> v8 = { 'w','x' };
std::vector<char> v9 = { 'y','z' };
dictionary.insert(std::make_pair(0, v0));
dictionary.insert(std::make_pair(1, v1));
dictionary.insert(std::make_pair(2, v2));
dictionary.insert(std::make_pair(3, v3));
dictionary.insert(std::make_pair(4, v4));
dictionary.insert(std::make_pair(5, v5));
dictionary.insert(std::make_pair(6, v6));
dictionary.insert(std::make_pair(7, v7));
dictionary.insert(std::make_pair(8, v8));
dictionary.insert(std::make_pair(9, v9));
}
3.切分
//如果字符串包含指定字符,则分割之后转换为数字。 不包含则按位切分
std::vector<int> SplitStringToDigit(std::string str, const std::string& reg)
{
std::vector<int> result;
if (str.find(reg) == std::string::npos)
{
for (char c : str)
{
result.push_back(c - '0');
}
return result;
}
else
{
std::string::size_type posLast = 0;
std::string::size_type posCurrent = str.find(reg);
while (posCurrent != std::string::npos)
{
result.push_back(str.substr(posLast, posCurrent - posLast).c_str()[0] - '0');
posLast = posCurrent + reg.size();
posCurrent = str.find(reg, posLast);
}
if (posLast < str.length())
{
result.push_back(str.substr(posLast).c_str()[0] - '0');
}
}
return result;
}
//题目也没有说输入的字符是否以空格排列, 此处考虑空格间隔情况
std::vector<char> SplitString(std::string str, const std::string& reg)
{
std::vector<char> result;
if (str.find(reg) == std::string::npos)
{
for (char c : str)
{
result.push_back(c);
}
return result;
}
else
{
std::string::size_type posLast = 0;
std::string::size_type posCurrent = str.find(reg);
while (posCurrent != std::string::npos)
{
result.push_back(str.substr(posLast, posCurrent - posLast).c_str()[0]);
posLast = posCurrent + reg.size();
posCurrent = str.find(reg, posLast);
}
if (posLast < str.length())
{
result.push_back(str.substr(posLast).c_str()[0]);
}
}
return result;
}
4.排列
//std::vector<std::vector<char>> 为一个动态的二维数组,一维指的是用户输入的数字, 二维指的是输入的数字所关联的字符
// i这里表示的是一维索引位置。 j表示的是二维索引位置
void GetPermuatations(int i,int j,std::vector<std::vector<char>>& sources, std::vector<std::vector<char>>& pers)
{
//如果超过了限定,就退出,避免递归死循环
if (i >= sources.size()) return;
if (i == 0 && j == 0)
{
for (int k = 0; k < sources[i].size(); k++)
{
std::vector<char> vs;
vs.push_back(sources[i][k]);
pers.push_back(vs);
}
}
else
{
//在上一轮的排列结果至上 继续进行新的元素的排列
std::vector<std::vector<char>> newPers;
for (auto& vect : pers)
{
for (int k = 0; k < sources[i].size(); k++)
{
std::vector<char> vs(vect);
vs.push_back(sources[i][k]);
newPers.push_back(vs);
}
}
pers.clear();
pers = newPers;
}
GetPermuatations(++i, ++j, sources, pers);
}
//字符集合 是否连续存在被忽略的字符信息
bool IsIgnore(const std::vector<char>& chrs, std::vector<char>& ignore)
{
std::sort(ignore.begin(), ignore.end());
if (chrs.size() < ignore.size())
return false;
char first = *ignore.begin();
auto iter=std::find(chrs.begin(), chrs.end(), first);
if (iter == chrs.end())
return false;
int start = std::distance(chrs.begin(), iter);
for (int i = start; i < ignore.size(); i++)
{
if (chrs[i] != ignore[i - start])
return false;
}
return true;
}
//字母组合的核心函数
std::vector<std::vector<char>> GetPermutation(std::vector<std::vector<char>>& sources, std::vector<char>& ignore)
{
std::vector<std::vector<char>> pers;
GetPermuatations(0,0, sources, pers);
std::vector<std::vector<char>> result;
//剔除掉被忽略的场景
for (auto& vect : pers)
{
if (!IsIgnore(vect, ignore))
{
result.push_back(vect);
}
}
return result;
}
完整代码
#include <iostream>
#include <vector>
#include <unordered_map>
#include <set>
#include <string>
#include <algorithm>
#pragma region 11
//如果字符串包含指定字符,则分割之后转换为数字。 不包含则按位切分
std::vector<int> SplitStringToDigit(std::string str, const std::string& reg)
{
std::vector<int> result;
if (str.find(reg) == std::string::npos)
{
for (char c : str)
{
result.push_back(c - '0');
}
return result;
}
else
{
std::string::size_type posLast = 0;
std::string::size_type posCurrent = str.find(reg);
while (posCurrent != std::string::npos)
{
result.push_back(str.substr(posLast, posCurrent - posLast).c_str()[0] - '0');
posLast = posCurrent + reg.size();
posCurrent = str.find(reg, posLast);
}
if (posLast < str.length())
{
result.push_back(str.substr(posLast).c_str()[0] - '0');
}
}
return result;
}
#pragma endregion
//题目也没有说输入的字符是否以空格排列, 此处考虑空格间隔情况
std::vector<char> SplitString(std::string str, const std::string& reg)
{
std::vector<char> result;
if (str.find(reg) == std::string::npos)
{
for (char c : str)
{
result.push_back(c);
}
return result;
}
else
{
std::string::size_type posLast = 0;
std::string::size_type posCurrent = str.find(reg);
while (posCurrent != std::string::npos)
{
result.push_back(str.substr(posLast, posCurrent - posLast).c_str()[0]);
posLast = posCurrent + reg.size();
posCurrent = str.find(reg, posLast);
}
if (posLast < str.length())
{
result.push_back(str.substr(posLast).c_str()[0]);
}
}
return result;
}
//集合中是否包含相同的元素 true:包含相同的元素
bool IsContainSameDigit(const std::vector<int>& nums)
{
std::set<int> se;
for (int i : nums)
{
se.insert(i);
}
if (se.size() != nums.size())
return true;
else
return false;
}
//std::vector<std::vector<char>> 为一个动态的二维数组,一维指的是用户输入的数字, 二维指的是输入的数字所关联的字符
// i这里表示的是一维索引位置。 j表示的是二维索引位置
void GetPermuatations(int i,int j,std::vector<std::vector<char>>& sources, std::vector<std::vector<char>>& pers)
{
//如果超过了限定,就退出,避免递归死循环
if (i >= sources.size()) return;
if (i == 0 && j == 0)
{
for (int k = 0; k < sources[i].size(); k++)
{
std::vector<char> vs;
vs.push_back(sources[i][k]);
pers.push_back(vs);
}
}
else
{
//在上一轮的排列结果至上 继续进行新的元素的排列
std::vector<std::vector<char>> newPers;
for (auto& vect : pers)
{
for (int k = 0; k < sources[i].size(); k++)
{
std::vector<char> vs(vect);
vs.push_back(sources[i][k]);
newPers.push_back(vs);
}
}
pers.clear();
pers = newPers;
}
GetPermuatations(++i, ++j, sources, pers);
}
//字符集合 是否连续存在被忽略的字符信息
bool IsIgnore(const std::vector<char>& chrs, std::vector<char>& ignore)
{
std::sort(ignore.begin(), ignore.end());
if (chrs.size() < ignore.size())
return false;
char first = *ignore.begin();
auto iter=std::find(chrs.begin(), chrs.end(), first);
if (iter == chrs.end())
return false;
int start = std::distance(chrs.begin(), iter);
for (int i = start; i < ignore.size(); i++)
{
if (chrs[i] != ignore[i - start])
return false;
}
return true;
}
//字母组合的核心函数
std::vector<std::vector<char>> GetPermutation(std::vector<std::vector<char>>& sources, std::vector<char>& ignore)
{
std::vector<std::vector<char>> pers;
GetPermuatations(0,0, sources, pers);
std::vector<std::vector<char>> result;
//剔除掉被忽略的场景
for (auto& vect : pers)
{
if (!IsIgnore(vect, ignore))
{
result.push_back(vect);
}
}
return result;
}
std::unordered_map<int, std::vector<char>> dictionary;
void InitDictionary()
{
std::vector<char> v0 = { 'a','b','c' };
std::vector<char> v1 = { 'd','e','f' };
std::vector<char> v2 = { 'g','h','i' };
std::vector<char> v3 = { 'j','k','l' };
std::vector<char> v4 = { 'm','n','o' };
std::vector<char> v5 = { 'p','q','r' };
std::vector<char> v6 = { 's','t' };
std::vector<char> v7 = { 'u','v' };
std::vector<char> v8 = { 'w','x' };
std::vector<char> v9 = { 'y','z' };
dictionary.insert(std::make_pair(0, v0));
dictionary.insert(std::make_pair(1, v1));
dictionary.insert(std::make_pair(2, v2));
dictionary.insert(std::make_pair(3, v3));
dictionary.insert(std::make_pair(4, v4));
dictionary.insert(std::make_pair(5, v5));
dictionary.insert(std::make_pair(6, v6));
dictionary.insert(std::make_pair(7, v7));
dictionary.insert(std::make_pair(8, v8));
dictionary.insert(std::make_pair(9, v9));
}
std::vector<std::vector<char>> GetDictionary(const std::vector<int>& nums)
{
std::vector<std::vector<char>> result;
for (int i : nums)
{
result.push_back(dictionary[i]);
}
return result;
}
void main()
{
InitDictionary();
std::string numString;
std::string ingnoreString;
std::getline(std::cin ,numString);
std::getline(std::cin, ingnoreString);
std::cout << std::endl;
std::string space = " ";
//分割字符串
std::vector<int> nums = SplitStringToDigit(numString, space);
bool isContainSameDigit = IsContainSameDigit(nums);
if (isContainSameDigit)
return;
std::vector<char> ignore = SplitString(ingnoreString, space);
//做完校验,获取到用户输入的信息之后 就可以开始 排列组合 剔除掉受影响的组合即可。 这里可以用排列组合,也可以用动态规划的思维来解决问题
std::vector<std::vector<char>> sources = GetDictionary(nums);
std::vector<std::vector<char>> result=GetPermutation(sources, ignore);
for (auto& vect : result)
{
std::string str;
for (char c : vect)
{
str += c;
}
std::cout << str << std::endl;
}
}
华为OD2024 E 文章被收录于专栏
实时更新华为2024 E卷答案