题源
383.赎金信
题目描述
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote 中使用一次。
示例 1:
输入:ransomNote = "a", magazine = "b"
输出:false
示例 2:
输入:ransomNote = "aa", magazine = "ab"
输出:false
示例 3:
输入:ransomNote = "aa", magazine = "aab"
输出:true
提示:
1 <= ransomNote.length, magazine.length <= 105
ransomNote 和 magazine 由小写英文字母组成
思考
思考一 – 哈希表 – 数组
如果magazine 中的每个字符只能在 ransomNote 中使用一次
那么magazine的长度必然>=ransomNote
开辟一个vector容器,先给magazine包含的字母计数+,再给ransomNote中的字母计数-,只要vector最
终没有负数元素,则返回true
剪枝
如果magazine的长度<ransomNote的长度,那么必然不能构成ransomNote,这就可以进行剪枝
实现思考一代码
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
//如果magazine 中的每个字符只能在 ransomNote 中使用一次,那么magazine的长度必然>=ransomNote
//哈希表 -- 数组
//开辟一个vector容器,先给magazine包含的字母计数+,再给ransomNote中的字母计数-,只要vector最终没有负数元素,则返回true
int mlength = magazine.length();
int rlength = ransomNote.length();
if(mlength < rlength) return false;
vector<int> count(26,0);
//给magazine包含的字母计数+
for (char c : magazine){
count[c-'a']++;
}
//再给ransomNote中的字母计数-
for (char c : ransomNote){
count[c-'a']--;
}
//判断有没有负数元素
for (int i : count){
//有负数元素
if(i < 0) return false;
}
//没有负数元素
return true;
}
};
最后剪枝的用时和不剪的用时一样
说明在这个题的样例中这种magazine的长度<ransomNote的长度的情况很少。
时间复杂度分析
三个循环的时间复杂度都是O(n)
综合来看,该算法的时间复杂度仍然是O(n)
思考一代码二
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int recode[26] = {0};
//这里可以不剪
// if(ransomNote.size() > magazine.size()){
// return false;
// }
for(int i = 0; i < magazine.length(); i++){
recode[magazine[i] - 'a']++;
}
for(int i = 0; i < ransomNote.length(); i++){
recode[ransomNote[i] - 'a']--;
if(recode[ransomNote[i] - 'a'] < 0){
return false;
}
}
return true;
}
};
反而更快
时间复杂度分析
两个循环的时间复杂度都是O(n)
综合来看,该算法的时间复杂度仍然是O(n)
思考二 – 暴力
用两层循环,外层循环表示magazine,内层循环表示ransomNote
在ransomNote中找到与magazine相同的字母,如有相同,将该
ransomNote的元素删除,然后遍历下一个magazine
最后判断ransomNote是否为空
实现思考二代码
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
for (int i = 0; i < magazine.size();i++){
for (int j = 0; j < ransomNote.size();j++){
if (magazine[i] == ransomNote[j]){
ransomNote.erase(ransomNote.begin()+j);
//不能重复使用同一个magazine[i]
break;
}
}
}
if (ransomNote.empty()) return true;
return false;
}
};
时间复杂度分析
两层for()循环的时间复杂度都是O(n^2)
erase 函数的时间复杂度通常是 O(n)
综合来看,该算法的时间复杂度仍然是O(n^3)