通过万岁!!!
- 题目:给你一个字符串S,由大小写字母和空格组成,然后给你一个字符串数组(这里面的字符串只有小写字母)。在字符串数组中找到一个字符串,能够将S中的所有字母(S中不区分大小写)都用完,可以不够,但是必须全都用完。如果有多个结果,则返回最短的哪个,如果还有多个最短的,就返回下标最小的。
- 思路:首先记录S都有那些字符,这里用一个长度为26的数组就可以了。因为后面我们不区分大小写,而且只看字母。然后遍历每个字符串,每次用一个就–,然后看看这个数组中还有没有大于0的数。如果有的话就说明S的字符没有完全用完。这是第一步的结果,但是还要求什么最短和下标小等。最终才得到最终结果。
- 技巧:
- 这里需要注意的是,我们记录S中字符个数的字符串,是需要还原的。我才用的方式是Copy一份。当然可以再遍历。
- 然后就是满足结果(能够把)的字符串需要记录。然后遍历找到长度最小的。这里记录的时候建议采用LinkedList。如果满足第一步的情况特别多的话,LinkedList应该会好点。
- 这里可以升级,我们可以直接在找到这个满足第一步结果的时候,记录要返回的下标,而下标的更新只有长度比已知最终的结果的小的时候才更新。
伪代码
定义一个LinkedList,用来记录所有满足第一步结果的字符串
定义长度为26的数组lic,用来记录每次字符出现的字数
for统计字符串中字符出现的次数
拷贝数组lic,得到licCopy
for遍历字符串数组
for遍历字符串数组中第i个字符串的字符
在licCopy中进行--
遍历licCopy数组,
查看是不是还有大于0的,如果有说明没有全部用完,第一步结果都不满足,重新还原licCopy数组,然后break;
如果是遍历到licCopy数组的最后一个,那么说明现在这个字符串是满足条件的,添加到LinkedList中,这里也要重新还原licCopy数组
遍历LinkedList,找到长度最小的,注意这里不用考虑下标,因为如果长度相等,不进行替换即可。
return 找到的字符串
java代码
class Solution {
public String shortestCompletingWord(String licensePlate, String[] words) {
LinkedList<String> ansList = new LinkedList();
int lic[] = new int[26];
int tempC = ' ';
for (int i = 0; i < licensePlate.length(); i++) {
tempC = licensePlate.charAt(i);
if (tempC > 64 && tempC < 91)
lic[tempC - 65]++;
if (tempC > 96 && tempC < 123)
lic[tempC - 97]++;
}
int[] licCopy = Arrays.copyOf(lic, 26);
for (int i = 0; i < words.length; i++) {
for (int j = 0; j < words[i].length(); j++) {
tempC = words[i].charAt(j);
if (tempC > 96 && tempC < 123)
licCopy[tempC - 97]--;
}
for (int j = 0; j < 26; j++) {
if (licCopy[j] > 0) {// 只要有大于0的,就返回
licCopy = Arrays.copyOf(lic, 26);
break;
}
if (j == 25) {// 最后一个并且没有返回
ansList.addLast(words[i]);
licCopy = Arrays.copyOf(lic, 26);
}
}
}
tempC = Integer.MAX_VALUE;
for (String s : ansList) {
if (tempC > s.length()) {
tempC = s.length();
words[0] = s;
}
}
return words[0];
}
}
伪代码——升级,主要是上面还需要再遍历LinkedList,其实我们可以再上面的双重for中直接得到想要的结果,这样就不用
LinkedList,并且少一次for
定义一个需要返回的字符串在字符串数组中的下标的变量,ansIdx
定义长度为26的数组lic,用来记录每次字符出现的字数
定义长度为26的数组licCopy
for统计字符串中字符出现的次数
for遍历字符串数组
for遍历字符串数组中第i个字符串的字符
在licCopy中进行--
遍历licCopy数组,
查看是不是还有大于0的,如果有说明没有全部用完,第一步结果都不满足,重新还原licCopy数组,然后break;
如果是遍历到licCopy数组的最后一个,那么说明现在这个字符串是满足条件的,但是需要判断这个字符串的长度是不是比已知的长度小,如果小才重新将新的下标赋值给ansIdx。并且也需要重新还原licCopy数组。
return 字符串数组[ansIdx];
java代码——升级
class Solution {
public String shortestCompletingWord(String licensePlate, String[] words) {
int ansIdx = -1;
int lic[] = new int[26];
int licCopy[] = new int[26];
int tempC = ' ';
for (int i = 0; i < licensePlate.length(); i++) {
tempC = licensePlate.charAt(i);
if (tempC > 64 && tempC < 91)
lic[tempC - 65]++;
if (tempC > 96 && tempC < 123)
lic[tempC - 97]++;
}
System.arraycopy(lic, 0, licCopy, 0, 26);
for (int i = 0; i < words.length; i++) {
for (int j = 0; j < words[i].length(); j++) {
tempC = words[i].charAt(j);
if (tempC > 96 && tempC < 123)
licCopy[tempC - 97]--;
}
for (int j = 0; j < 26; j++) {
if (licCopy[j] > 0) {// 只要有大于0的,就返回
System.arraycopy(lic, 0, licCopy, 0, 26);
break;
}
if (j == 25) {// 最后一个并且没有返回
System.arraycopy(lic, 0, licCopy, 0, 26);
if (ansIdx == -1) {
ansIdx = i;
break;
}
if (words[ansIdx].length() > words[i].length())
ansIdx = i;
}
}
}
return words[ansIdx];
}
}
- 总结:题目不难,就是转变成便利字符即可。注意数组的拷贝后来使用System.arraycopy是因为他的效率比较高。做算法题需要循序渐进,先通过,然后再看看可不可以优化,如果直接想优化的方式,还是比较困难的。优化的方式可以慢慢思索,题目做多了也就有经验了。