题目:
给定一个单词列表,我们将这个列表编码成一个索引字符串 S 与一个索引列表 A。
例如,如果这个列表是 [“time”, “me”, “bell”],我们就可以将其表示为 S = “time#bell#” 和 indexes = [0, 2, 5]。
对于每一个索引,我们可以通过从字符串 S 中索引的位置开始读取字符串,直到 “#” 结束,来恢复我们之前的单词列表。
那么成功对给定单词列表进行编码的最小字符串长度是多少呢?
示例:
输入: words = [“time”, “me”, “bell”]
输出: 10
说明: S = “time#bell#” , indexes = [0, 2, 5] 。
思路:
首先这个题理解起来有点难度,因为time后面有me,所以复用me就可以,me的部分就可以压缩掉。举个更好理解的例子:[“me”,“time”,“ime”];压缩完后,time#,索引为[2,0,1]。每次读的时候从当前位置读到#即可,所以从2位置到#,me;从0位置到#,time;从1位置到#,ime。
这么说是不是就可以解释了。其实也就是如果该字串是某个字串的后子串。什么是后子串,就是该子串从后面能和某个字符串后面的匹配。比如:time和me,me能从后面e匹配,m匹配。那么me就是time的后子串。
所以这其实是个后子串匹配题。首先我们用暴力解法,申请一个数组,存放结果字符串,如果现在的字串是结果字符串里某个的子串,跳过,对比下一个;如果现在的字串在结果字串里有后子串,那么将该字符串覆盖进去,将少的长度补上。如果没有子串关系,直接放入结果字串。
暴力解法代码如下:
class Solution {
public:
bool matchStr(string& res1,string& res2)
{
int len1=res1.length();
int len2=res2.length();
while(len1>=1&&len2>=1&&res1[len1-1]==res2[len2-1])
{
len1--;
len2--;
}
if(len2==0)
{
return true;
}
return false;
}
int minimumLengthEncoding(vector<string>& words) {
int length=words.size();
if(length==1)
return words[0].length()+1;
vector<string> ans(2000);
int resultSize=0;
int index=0;
for(int i=0;i<length;i++)
{
bool flg=0;
for(int j=0;j<index;j++)
{
if(matchStr(words[i],ans[j]))
{
resultSize+=words[i].length()-ans[j].length();
ans[j]=words[i];
flg=1;
break;
}
else if(matchStr(ans[j],words[i]))
{
flg=1;
break;
}
}
if(!flg)
{
ans[index]=words[i];
index++;
resultSize+=words[i].length()+1;
}
}
return resultSize;
}
};
从暴力解法可以看出,我们要进行两次对比,因为我们不确定谁是谁的子串。但其实,短的可能是子串,长的一定不会是子串。而且我们对比时是从后往前对比,所以我们可以按后面的字母先排序,一样则前一位排序。比如:time,lime,me,mad排完序-me,lime,time,mad。这里面me,lime怎么排,我们说过,长的一定不会是子串,所以我们在排序后,长的放在后面,这样我们只需要把前一个和后一个比就行了。
这里面有个自定义排序,之前做过,后来有点忘却了,今天重新复习一遍。cmp函数,参数(a,b),当返回结果为true时,不交换,false时,交换。看下面代码,当c1!=c2时,如果c1<c2,说明就是前面比后面小,不需要交换。len1<len2,也不需要。
canmatch函数是用来判断是否是子串的。
最后代码献上。
class Solution {
public:
static bool cmp(string& tmp1, string& tmp2)
{
int len1 = tmp1.length();
int len2 = tmp2.length();
for (int i = 0; i < min(len1, len2); i++) {
char c1 = tmp1[len1-1-i];
char c2 = tmp2[len2-1-i];
if (c1 != c2) {
return c1 < c2;
}
}
return len1<len2;
}
bool canmatch(string& res1,string& res2)
{
int len1=res1.length();
int len2=res2.length();
while(len1>=1&&res1[len1-1]==res2[len2-1])
{
len1--;
len2--;
}
if(len1==0)
{
return true;
}
return false;
}
int minimumLengthEncoding(vector<string>& words) {
int length=words.size();
if(length==1)
return words[0].length()+1;
sort(words.begin(),words.end(),cmp);
int count=0;
for(int i=0;i<length;i++)
{
if(i+1<length&&canmatch(words[i],words[i+1]))
{
continue;
}
else
{
count+=words[i].length()+1;
}
}
return count;
}
};
这个题耗了大概一个小时的时间才完善了第二个代码,总结起来都是一些小细节方面的错误,所以编程还是一个考虑细节的东西。
加油,冲冲冲。