华为OD机考题目《敏感字加密》100分题目


牛客上看到有个同学发了这么一道题,题目是  敏感字加密。

保险起见,我把他帖子截图进来了,感谢 @唐浮 提供的素材。处于个人兴趣,我简单做了一下。


首先谈一下我对这道题的理解: 这道题就是给你一个字符串,下划线分割,让你拆开,然后将第 k 个 改为  ******  然后再拼回去。 特殊地,它会有一些 value中包含下划线,但是会被 双引号包围起来,就这一点难度。
如果没有这个特殊的点,那就更简单了。

我的思路是,写一个split函数(c++没有现成的split函数,需要自己写一个),把题目要求的分隔方式实现出来,分割到一个vector里去,然后,如果个数大于等于k,则将第k个改为 ******,如果个数不足k个,则输出ERROR 。
题目中没有说有多组用例,所以不需要用 while(cin>>xxxx)。


//我的主要代码片段如下
int main()
{
    int k;
    string str;
    cin >> k >> str;

    vector<string> res;
    //split是自定义函数,实现了根据下划线分割字符串,特殊地,如果下划线被双引号包围,则不认为它是一个分隔符。
    split(str, res, '_');

    //如果分割出来的命令字个数不足k个,则无法将第K个加密,所以要输出ERROR
    if (k >= res.size())
    {
        cout << "ERROR" << endl;
        return 0;
    }

    //将第k个加密
    res[k] = "******";

    do_cout(res);//按顺序并拼接下划线打印
    return 0;
}


其中,split函数我是这样实现的:
//split实现将str按照ch分隔,按顺序写入 rVector中。特殊的,如果ch被双引号包围,则不认为它是分隔符
void split(const string& str, vector<string>& rVector, char ch)
{
    std::string::size_type startPos = 0;
    std::string::size_type endPos = str.find(ch, startPos);

    while (endPos != std::string::npos)
    {
        rVector.push_back(str.substr(startPos, endPos - startPos));
        startPos = endPos + 1;
        if (str[startPos] == '\"')
        {
            endPos = str.find('\"', startPos+1);
            endPos++;//题目规定必然能找到下一个双引号,所以无需做npos判断。
        }
        else
        {
            endPos = str.find(ch, startPos);
        }
    }

    rVector.push_back(str.substr(startPos));

}


最后,我的打印函数是这样写的,这个就没啥技术含量了,就是注意最后不要多一个下划线。
void do_cout(vector<string>& res)
{
    //to do
    for (int i = 0; i < res.size(); i++) 
    {
        cout << res[i];
        if (i != res.size() - 1)
        {
            cout << "_";
        }
    }
    cout << endl;
}

需要注意的是,被调用的函数,要写在 main函数上方(因为都在cpp文件中),所以整体下来是这样的(代码已忽略 包含的头文件):
void split(const string& str, vector<string>& rVector, char ch)
{
    std::string::size_type startPos = 0;
    std::string::size_type endPos = str.find(ch, startPos);

    while (endPos != std::string::npos)
    {
        rVector.push_back(str.substr(startPos, endPos - startPos));
        startPos = endPos + 1;
        if (str[startPos] == '\"')
        {
            endPos = str.find('\"', startPos+1);
            endPos++;//题目规定必然能找到下一个双引号,所以无需做npos判断。
        }
        else
        {
            endPos = str.find(ch, startPos);
        }
    }

    rVector.push_back(str.substr(startPos));

}

void do_cout(vector<string>& res)
{
    //to do
    for (int i = 0; i < res.size(); i++) 
    {
        cout << res[i];
        if (i != res.size() - 1)
        {
            cout << "_";
        }
    }
    cout << endl;
}

int main()
{
    int k;
    string str;
    cin >> k >> str;

    vector<string> res;
    //split是自定义函数,实现了根据下划线分割字符串,特殊地,如果下划线被双引号包围,则不做分割。
    split(str, res, '_');

    if (k >= res.size())
    {
        cout << "ERROR" << endl;
        return 0;
    }

    res[k] = "******";

    do_cout(res);//按顺序并拼接下划线打印
    return 0;
}


如果题目中说明“注意:题目包含多组用例”

则 整体的main函数要改为这样():
int main()
{
    int k;
    string str;
    while (cin >> k >> str)//将此处改为 while,VS2017在本地退不出,但实际牛客网的用例可以过并可以退出。
    {
        vector<string> res;
        split(str, res, '_');
        if (k >= res.size())
        {
            cout << "ERROR" << endl;
            continue;//这里不再是return 0,而是 continue,表示这个循环到此结束,继续下一个循环。
        }
        res[k] = "******";
        do_cout(res);
    }
    return 0;
}


如果题目中,没有说明 命令字里包含 下划线,则 只需要修改split函数即可:
void split(const std::string& str, char ch, std::vector<std::string>& rVector)
{
    std::string::size_type startPos = 0;
    std::string::size_type endPos = std::string::npos;
    while ((endPos = str.find(ch, startPos)) != std::string::npos)
    {
        rVector.push_back(str.substr(startPos, endPos - startPos));
        startPos = endPos + 1; 
    }
    rVector.push_back(str.substr(startPos));
}


上述代码并未经过实际验证是否可以拿满分,如果有瑕疵,可以稍作调试和修改。
本人已验证 当输入字符串为 a_"1_2"_3_""_5 时, k = 0 1 2 3 4 5 的 五个场景,结果如下:


有兴趣的同学可以用其他语言试一下。

楼主提供的三道题中,另外两道题,等有空了我再试试。

如果大家有更好的写法,欢迎留言讨论。



网友提供的一份java代码,PS:个人认为这个代码毫无可读性,所有方法全部平铺到一个main函数里了,有很大的优化空间。
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scanner=new Scanner(System.in);
        int k=Integer.parseInt(scanner.nextLine());
        String s= scanner.nextLine();
		
		//用下面的for循环将s拆分开,建议把这一段分装一个函数出去。
        ArrayList<String> coms=new ArrayList<>();
        for(int i=0;i<s.length();){
			//如果遇到双引号,则去找下一个双引号,两个双引号之间(含双引号)作为本次命令字
            if(s.charAt(i)=='"'){
                int j=i+1;
                for(;j<s.length();j++){
                    if(s.charAt(j)=='"'){
                        break;
                    }
                }
                coms.add(s.substring(i,j+1));
                i=j+1;
                continue;
            }
			
			//如果s的第i位不是下划线,也不是双引号,则找下一个下划线,并把第i位到下一个下划线之间位置一个命令字。
            if(s.charAt(i)!='_'&&s.charAt(i)!='"'){
                int j=i+1;
                for(;j<s.length();j++){
                    if(s.charAt(j)=='_'){
                        break;
                    }
                }
                coms.add(s.substring(i,j));
                i=j;
                continue;
            }
			
			//如果是下划线,则跳过
            if(s.charAt(i)=='_'){
                i++;
                continue;
            }
 
        }
		
		//如果超限,则打印ERROR
        String out="";
        if(k>=coms.size()){
            System.out.println("ERROR");
            return;
        }
		//用最笨的方式将第k个命令字改为******
        for(int i=0;i<coms.size()-1;i++){
            if(i!=k){
                out=out+coms.get(i)+"_";
            }else {
                out=out+"******"+"_";
            }
 
        }
		
		//用最笨的方法拼接打印元素out
        if(k==coms.size()-1){
            out=out+"******";
        }else {
            out=out+coms.get(coms.size()-1);
        }
 
        System.out.println(out);
        return;
    }
}




全部评论
这道题刚做过,用例通过了85% 想不到还有哪里没考虑到😓 我考虑到的点就是1.连续下划线处理2.ERROR处理3.带引号命令处理,且引号中可能出现多个下划线
点赞 回复 分享
发布于 2022-07-01 11:23
敏感字段的是不是没考虑连续下划线的用例
点赞 回复 分享
发布于 2022-06-14 12:59

相关推荐

不吃牛肉的选手在刷面试经:首先,你数过吗?其次,他知道吗?最后,你说了他信吗?
点赞 评论 收藏
分享
评论
点赞
7
分享

创作者周榜

更多
牛客网
牛客企业服务