[LeetCode 383] Ransom Note

"喜刷刷 "

Posted by Devin on September 1, 2016

问题描述

Given
 an 
arbitrary
 ransom
 note
 string 
and 
another 
string 
containing 
letters from
 all 
the 
magazines,
 write 
a 
function 
that 
will 
return 
true 
if 
the 
ransom 
 note 
can 
be 
constructed 
from 
the 
magazines ; 
otherwise, 
it 
will 
return 
false. 



Each 
letter
 in
 the
 magazine 
string 
can
 only 
be
 used 
once
 in
 your 
ransom
 note.

Note: You may assume that both strings contain only lowercase letters.

canConstruct("a", "b") -> false
canConstruct("aa", "ab") -> false
canConstruct("aa", "aab") -> true

解法一

解题思路:

根据题意, 意思是一个字符串中是否包含另一个字符串中的所有字母, 包括个数, 理解题意就很简单了, 直接使用一个数组来统计各个字符的数量, 然后进行比较即可.

代码实现:

    private boolean canConstruct(String ransomNote, String magazine) {
        int[] chars = new int[26];
        for (int i = 0; i < magazine.length(); i++) {
            chars[magazine.charAt(i) - 'a']++;
        }
        for (int i = 0; i < ransomNote.length(); i++) {
            //如果该字母个数小于零, 则说明magazine中不能全包含该字母
            if (--chars[ransomNote.charAt(i) - 'a'] < 0) return false;
        }
        return true;
    }

解法二

解题思路:

思路跟解法一类似, 这里使用Java API HashMap实现.

代码实现:

    private boolean canConstruct1(String ransomNote, String magazine){
        HashMap<Character,Integer> charsMap = new HashMap<>(magazine.length());
        for (int i = 0; i < magazine.length(); i++) {
            if (charsMap.containsKey(magazine.charAt(i))){
                charsMap.put(magazine.charAt(i), charsMap.get(magazine.charAt(i)) + 1);
            }else {
                charsMap.put(magazine.charAt(i), 1);
            }
        }
        for (int i = 0; i < ransomNote.length(); i++) {
            if (charsMap.containsKey(ransomNote.charAt(i))){
                //当字母个数为1时,则应该去除该节点
                if (charsMap.get(ransomNote.charAt(i)) == 1){
                    charsMap.remove(ransomNote.charAt(i));
                }else{
                    charsMap.put(ransomNote.charAt(i), charsMap.get(ransomNote.charAt(i)) - 1);
                }
            }else {
                //当字母不存在时,说明magazine中不能全包含该字母,直接返回false.
                return false;
            }
        }
        return true;
    }

总结

理解题意后, 这道题很简单, 通过这两种解法的主要是为了分别对比使用原生代码实现和使用Java API实现时在性能上的差异,其中解法一在LeetCode上的运行为20ms,而解法二使用了85ms,足足是解法一的四倍多时间,所以日常我们在实现方法时,特别是那些经常被调用的代码,我们可以尽量使用原生代码实现.