题目的主要信息:

输入关键字,以“最短唯一匹配原则”匹配命令:

  • 若只输入一字串,则只匹配一个关键字的命令行。
  • 若只输入一字串,但本条命令有两个关键字,则匹配失败。
  • 若输入两字串,则先匹配第一关键字,如果有匹配但不唯一,继续匹配第二关键字,如果仍不唯一,匹配失败。
  • 若输入两字串,则先匹配第一关键字,如果有匹配但不唯一,继续匹配第二关键字,如果唯一,匹配成功。
  • 若输入两字串,第一关键字匹配成功,则匹配第二关键字,若无匹配,失败。
  • 若匹配失败,打印“unknown command”

方法一:

用cmdin储存所有可能的命令行,命令行分为两部分存储。首先将输入的字符串按照空格划分为s1和s2,如果该字符串有两个关键字则s2不为空。然后遍历一遍cmdin进行匹配,如果第一个关键字匹配成功,且第二个匹配成功或没有第二个关键字,则表示命令匹配成功。匹配命令用的find函数。用count1统计第一个关键字匹配成功的数量,count2统计第二个关键字匹配成功的数量。最后,如果两个关键字都匹配成功,且只有一组匹配即count1=count2=1,则匹配成功。 alt 具体做法:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main(){
    vector<pair<string, string>> cmdin = { { "reset","" } ,{ "reset","board" } ,{ "board","add" } ,{ "board","delete" } ,{ "reboot","backplane" } ,{ "backplane","abort" } };
    vector<string> cmdout = { "reset what" ,"board fault" ,"where to add" ,"no board at all" ,"impossible" ,"install first" };
    string s;
    while (getline(cin,s)){
        string s1 , s2;
        int pos = 0;
        //以空格为分界划分
        while (pos < s.size() && s[pos] != ' '){//遍历一遍找到空格的位置
            pos++;
        }
        s1 = s.substr(0, pos);
        if (pos != s.size()){
            s2 = s.substr(pos + 1, s.size());
        }
		int count1 = 0, count2 = 0;
		string result;
		for (auto iter=cmdin.begin();iter!=cmdin.end();iter++){
			int flag1 = iter->first.find(s1) == 0? 1 : 0;//判断第一个关键字是否匹配
			int flag2;
			if (s2 != "") {
				flag2 = iter->second.find(s2) == 0? 1 : 0;//判断第二个关键字是否匹配
			}else if(s2==""&&iter->second==""){//如果没有第二个关键字,默认匹配成功
				flag2 = 1;
			}else{
                flag2 = 0;
            }
			if (flag1 && flag2)//两个关键字都匹配上了
			{
				count1++;
				count2++;
				result = cmdout[iter - cmdin.begin()];
			}
		}
		if (count1 == 1 && count2 == 1){//两个关键字都匹配成功,且只有一组匹配
			cout << result << endl;
		}else {//匹配失败或有多组匹配
			cout << "unknown command" << endl;
		}
	}
	return 0;
}

复杂度分析:

  • 时间复杂度:O(1),对于每一个输入的子串都只需要常数时间匹配和比较。
  • 空间复杂度:O(1),只用了常数空间。

方法二:

正则表达式。整体思路和方法一相同,方法一匹配的方法是用find函数,方法二将匹配的方法改为正则表达式,正则表达式为关键字加上若干个小写字母拼接而成,两个关键字分别匹配,如果两个关键字都匹配成功,且只有一组配对,则整个命令匹配成功。

具体做法:

#include <iostream>
#include <string>
#include <regex>
#include <vector>

using namespace std;

int main(){
    vector<pair<string, string>> cmdin = { { "reset","" } ,{ "reset","board" } ,{ "board","add" } ,{ "board","delete" } ,{ "reboot","backplane" } ,{ "backplane","abort" } };
    vector<string> cmdout = { "reset what" ,"board fault" ,"where to add" ,"no board at all" ,"impossible" ,"install first" };
    string s;
    while (getline(cin,s)){
        string s1 , s2;
        int pos = 0;
        //以空格为分界划分
        while (pos < s.size() && s[pos] != ' '){//遍历一遍找到空格的位置
            pos++;
        }
        s1 = s.substr(0, pos);
        if (pos != s.size()){
            s2 = s.substr(pos + 1, s.size());
        }
		int count1 = 0, count2 = 0;
		string result;
		for (auto iter=cmdin.begin();iter!=cmdin.end();iter++){
            string pattern1 = s1 + "[a-z]*";//正则表达式
            int flag1 = regex_match(iter->first, regex(pattern1));//第一个关键字匹配
            string pattern2 = s2 + "[a-z]*";//正则表达式
            int flag2 = 0;
            if((s2 == "" && iter->second == "")){
                flag2 = 1;
            }else if(s2 != ""){
                flag2 = regex_match(iter->second, regex(pattern2));//第二个关键字匹配
            }
            if (flag1 && flag2)//两个关键字都匹配上了
			{
				count1++;
				count2++;
				result = cmdout[iter - cmdin.begin()];
			}
		}
		if (count1 == 1 && count2 == 1){//两个关键字都匹配成功,且只有一组匹配
			cout << result << endl;
		}else {//匹配失败或有多组匹配
			cout << "unknown command" << endl;
		}
	}
	return 0;
}

复杂度分析:

  • 时间复杂度:O(1),对于每一个输入的子串都只需要常数时间匹配和比较。
  • 空间复杂度:O(1),只用了常数空间。