字母组合

一.题目

二.歧义

这题目文字描述和样例没有讲清楚:

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卷答案

全部评论

相关推荐

已化身鹅黑有缘再见吧:好想电梯故障直接摔死啊 不想做实验 不想写论文 不想面试了
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务