哈希表6:赎金信(383)

本题如下:(链接:https://leetcode.cn/problems/ransom-note/)

题目:给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false 。

magazine 中的每个字符只能在 ransomNote 中使用一次。

 

 

 

 

思路:

这道题目和题库第242题有效的字母异位词很像,但有效的字母异位词这题相当于求字符串a 和 字符串b 是否可以相互组成 ,而这道题目是求字符串a能否组成字符串b,而不用管字符串b能不能组成字符串a。

本题判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成,但是这里需要注意两点。

(1)第一点“为了不暴露赎金信字迹,要从杂志上搜索各个需要的字母,组成单词来表达意思”  这里说明杂志里面的字母不可重复使用。

(2)第二点 “你可以假设两个字符串均只含有小写字母。” 说明只有小写字母,这一点很重要。

 

解法:

(1)对于本题的第一个思路其实就是暴力枚举了,两层for循环,不断去寻找,代码如下:

 1 // 时间复杂度: O(n^2)
 2 // 空间复杂度:O(1)
 3 class Solution {
 4 public:
 5     bool canConstruct(string ransomNote, string magazine) {
 6         for (int i = 0; i < magazine.length(); i++) {
 7             for (int j = 0; j < ransomNote.length(); j++) {
 8                 // 在ransomNote中找到和magazine相同的字符
 9                 if (magazine[i] == ransomNote[j]) {
10                     ransomNote.erase(ransomNote.begin() + j); // ransomNote删除这个字符
11                     break;
12                 }
13             }
14         }
15         // 如果ransomNote为空,则说明magazine的字符可以组成ransomNote
16         if (ransomNote.length() == 0) {
17             return true;
18         }
19         return false;
20     }
21 };

这种方法的时间复杂度是比较高的,而且里面还有一个字符串删除也就是erase的操作,也是费时的,当然这段代码也可以解决这道题。

 

(2)哈希法

因为这道题目只有小写字母,那么就可以采用空间换取时间的哈希策略, 用一个长度为26的数组去记录magazine里字母出现的次数。

然后再用ransomNote去验证这个数组是否包含了ransomNote所需要的所有字母。

因此这道题依然是数组在哈希法中的应用。

但其实在本题的情况下,如果使用map的空间消耗要比数组大一些的,因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的,数据量大的话就能体现出来差别了。 所以本题使用数组更加简单直接有效!

C++代码如下:

 1 // 时间复杂度: O(n)
 2 // 空间复杂度:O(1)
 3 class Solution {
 4 public:
 5     bool canConstruct(string ransomNote, string magazine) {
 6         int record[26] = {0};
 7         //add
 8         if (ransomNote.size() > magazine.size()) {
 9             return false;
10         }
11         for (int i = 0; i < magazine.length(); i++) {
12             // 通过recode数据记录 magazine里各个字符出现次数
13             record[magazine[i]-'a'] ++;
14         }
15         for (int j = 0; j < ransomNote.length(); j++) {
16             // 遍历ransomNote,在record里对应的字符个数做--操作
17             record[ransomNote[j]-'a']--;
18             // 如果小于零说明ransomNote里出现的字符,magazine没有
19             if(record[ransomNote[j]-'a'] < 0) {
20                 return false;
21             }
22         }
23         return true;
24     }
25 };

 

接下来给出相应的Java版本:

 1 class Solution {
 2     public boolean canConstruct(String ransomNote, String magazine) {
 3         // 定义一个哈希映射数组
 4         int[] record = new int[26];
 5 
 6         // 遍历
 7         for(char c : magazine.toCharArray()){
 8             record[c - 'a'] += 1;
 9         }
10 
11         for(char c : ransomNote.toCharArray()){
12             record[c - 'a'] -= 1;
13         }
14         
15         // 如果数组中存在负数,说明ransomNote字符串总存在magazine中没有的字符
16         for(int i : record){
17             if(i < 0){
18                 return false;
19             }
20         }
21 
22         return true;
23     }
24 }

 

posted @ 2022-09-11 17:30  Ricentch  阅读(48)  评论(0)    收藏  举报