You are given a String number containing the digits of a phone number (the number of digits, n, can be any positive integer) . To help you memorize the number, you want to divide it into groups of contiguous digits. Each group must contain exactly 2 or 3 digits. There are three kinds of groups:
-
Excellent: A group that contains only the same digits. For example, 000 or 77.
-
Good: A group of 3 digits, 2 of which are the same. For example, 030, 229 or 166.
-
Usual: A group in which all the digits are distinct. For example, 123 or 90.
The quality of a group assignment is defined as 2 × (number of excellent groups) + (number of good groups), Divide the number into groups such that the quality is maximized. Design an e-cient algorithm to return the solution that maximizes the quality.
分析:从头开始扫描phone number,第一个group可以是2或者3个字符,分别计算剩下的序列的quality,最后得到整个序列的最大quality。此处可以使用递归,但是需要注意,可能存在重复计算的情况,可以使用数组来保存已经计算过的子序列的max quality,避免递归时的重复计算。
//返回group的quality值
static int GroupQuality(const char* group, int len){
assert(len==2 || len==3);
int quality = 0;
if (group[0] == group[1]){
if (len==2 || (len==3&&group[1]==group[2]))
quality = 2;
else
quality = 1;
} else if (len == 3 && (group[0]==group[2] || group[1]==group[2])){
quality = 1;
}
return quality;
}
//计算phoneNumber的第一个分组字符数为firstGroup时对应的最大quality值和相应分组
static int PhoneNumberQuality(const char* phoneNumber, int numberLen, int firstGroup, int qualities[], string groups[], string& group){
int quality = -1;
group = "";
if (numberLen==firstGroup || numberLen-firstGroup>=2){
quality = GroupQuality(phoneNumber, firstGroup);
group = string(phoneNumber, firstGroup);
if (numberLen-firstGroup>=2){
PhoneNumberSplit(phoneNumber+firstGroup, numberLen-firstGroup, qualities+firstGroup, groups+firstGroup);
quality += qualities[firstGroup];
group += "-"+groups[firstGroup];
}
}
return quality;
}
//递归计算phoneNumber[0..numberLen-1]每个位置对应的最大quality值和相应的分组
static void PhoneNumberSplit(const char* phoneNumber, int numberLen, int qualities[], string groups[]){
if (qualities[0] >= 0)
return;
assert(numberLen>=2);
int quality = -1;
string group;
string tmpGroup;
//第一个分组时3个字符的情况
int tmpQuality = PhoneNumberQuality(phoneNumber, numberLen, 3, qualities, groups, tmpGroup);
if (tmpQuality>quality){
quality = tmpQuality;
group = tmpGroup;
}
//第一个分组时2个字符的情况
tmpQuality = PhoneNumberQuality(phoneNumber, numberLen, 2, qualities, groups, tmpGroup);
if (tmpQuality>quality){
quality = tmpQuality;
group = tmpGroup;
}
qualities[0] = quality;
groups[0] = group;
}
//返回电话号码进行分组后的最大Quality值,group返回具有最大Quanlity值得分组
int PhoneNumberSplit(const string& phoneNumber, string& group){
int numberLen = phoneNumber.length();
assert(numberLen>=2);
int* qualities = new int[numberLen];
memset(qualities, -1, sizeof(int)*numberLen); //qualities[i]==-1表示第i个字符的quality值尚未计算
string* groups = new string[numberLen]; //存放qualities对应的分组情况
PhoneNumberSplit(phoneNumber.c_str(), numberLen, qualities, groups);
int maxQuality = qualities[0];
group = groups[0];
delete[] qualities;
delete[] groups;
return maxQuality;
}