leetcode(String)–383. 赎金信
1,题目:
2,思路:
方法一:排序与双指针:
- 1.题目要求magazine中的字母是否可以构成ransomNote,且magazine中的字母不能重复使用。那么对于ransomNote中的每一个字符,都去magazine中查找是否存在(找到一个后,要从magazine中剔除)。
- 2.用暴力查找太慢。借鉴判断字符串相等的思路,双指针分别指向两个字符串的第一个字符,依次对比,双指针一起移动。我们可以将magazine与ransomNote对应的字符数组m与r进行排序,然后使用双指针逐一对比字符。
- 3.用指针i指向r[]的第一个字符,用j指向m的第一个字符。之后对于两个字符数组中的字符进行判断,为了防止索引越界,循环条件为while(i< r.length && j < m.length)。
- 4.当r[i] > m[j]时,m中当前字符不能拿来构成r[i],尝试用m中的下一个字符j++
- 5.当r[i] < m[j]时,m中当前字符已经验证过无法构成r[i]而m中当前元素及后续元素都比r[i]大,所以r[i]这个字符找不到可以构建的,答案就是return
false - 6.其余情况,即r[i] == m[j],r[i]找到可以用于构建的,所以去判断下一个字符r++,注意由于magazine中字母不能重复使用,所以j++使用m中下一个字母。
- 7.当循环结束后,如果i == r.length说明对于r中的每个字母都在m中找到对应的字母,此时可以按照题目要求构建出randomNote,返回true,否则返回false。
- 8.双指针的遍历是线性的,但是排序是线性对数的,所以时间复杂度为O(nlog(n)+mlog(m))O(nlog(n)+mlog(m)),空间复杂度为O(m
- n)O(m+n)。
方法二:hashmap:
解题思路
此处撰写解题思路
正如题目所示,使用hashmap统计字符出现的次数,只要赎金信里有的,杂志都有而且足够即可。
遍历一遍,时间为o(lr + lm),lr,lm分别为两者的长度
使用一个map,空间为o(lm)
首先想到java的HashMap,对字符进行计数,赎金信中的所有字符,杂志中都要有,而且,数量不能少于赎金信(key表示这个字符,value表示这个字符出现的次数)
3,代码:
方法一:排序与双指针:
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
/*
1.题目要求magazine中的字母是否可以构成ransomNote,且magazine中的字母不能重复使用。那么对于ransomNote中的每一个字符,都去magazine中查找是否存在(找到一个后,要从magazine中剔除)。
2.用暴力查找太慢。借鉴判断字符串相等的思路,双指针分别指向两个字符串的第一个字符,依次对比,双指针一起移动。我们可以将magazine与ransomNote对应的字符数组m与r进行排序,然后使用双指针逐一对比字符。
3.用指针i指向r[]的第一个字符,用j指向m的第一个字符。之后对于两个字符数组中的字符进行判断,为了防止索引越界,循环条件为while(i < r.length && j < m.length)。
4.当r[i] > m[j]时,m中当前字符不能拿来构成r[i],尝试用m中的下一个字符j++
5.当r[i] < m[j]时,m中当前字符已经验证过无法构成r[i]而m中当前元素及后续元素都比r[i]大,所以r[i]这个字符找不到可以构建的,答案就是return false
6.其余情况,即r[i] == m[j],r[i]找到可以用于构建的,所以去判断下一个字符r++,注意由于magazine中字母不能重复使用,所以j++使用m中下一个字母。
7.当循环结束后,如果i == r.length说明对于r中的每个字母都在m中找到对应的字母,此时可以按照题目要求构建出randomNote,返回true,否则返回false。
8.双指针的遍历是线性的,但是排序是线性对数的,所以时间复杂度为O(nlog(n)+mlog(m))O(nlog(n)+mlog(m)),空间复杂度为O(m + n)O(m+n)。
*/
char[] r = ransomNote.toCharArray();
char[] m = magazine.toCharArray();
Arrays.sort(r);
Arrays.sort(m);
int i = 0, j = 0;
while(i < r.length && j < m.length){
if(r[i] > m[j]) j++;//m中当前字符不能拿来构成r[i],尝试用m中的下一个字符j++
else if (r[i] < m[j]) return false;//m中当前字符已经验证过无法构成r[i]而m中当前元素及后续元素都比r[i]大,所以r[i]这个字符找不到可以构建的,答案就是return false
else { // 一个字母只能用一次,所以当相等时,两个指针都需要移动
i++;
j++;
}
}
return i == r.length;//当循环结束后,如果i == r.length说明对于r中的每个字母都在m中找到对应的字母,此时可以按照题目要求构建出randomNote,返回true,否则返回false
}
}
方法二:hashmap:
/*
解题思路
此处撰写解题思路
正如题目所示,使用hashmap统计字符出现的次数,只要赎金信里有的,杂志都有而且足够即可。
遍历一遍,时间为o(lr + lm),lr,lm分别为两者的长度
使用一个map,空间为o(lm)
*/
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
//首先想到java的HashMap,对字符进行计数,赎金信中的所有字符,杂志中都要有,而且,数量不能少于赎金信(key表示这个字符,value表示这个字符出现的次数)
// Map<Character, Integer> ran = new HashMap<>();
Map<Character, Integer> mag = new HashMap<>();
for(char ch: magazine.toCharArray()){
if(mag.containsKey(ch)) mag.put(ch, mag.get(ch)+1);//mag.get(ch)+1就是当前这个字符出现了不止一次,表示计数的功能
else mag.put(ch, 1);//否则就是这个歌字符第一次出现,所以次数为1
}
for(char ch: ransomNote.toCharArray()){
if(!mag.containsKey(ch))
return false;//如果赎金信里面的字母,杂志中没有
else if(mag.get(ch)==0) return false;//如果杂志中的字符不够
else mag.put(ch, mag.get(ch)-1);//就是这个字符在mag中出现了,所以次数减一,因为一个已经匹配上了。
}
return true;
}
}