1. 程式人生 > >LeetCode演算法題-Ransom Note(Java實現)

LeetCode演算法題-Ransom Note(Java實現)

這是悅樂書的第212次更新,第225篇原創

01 看題和準備

今天介紹的是LeetCode演算法題中Easy級別的第80題(順位題號是383)。給定一個任意贖金票據字串和另一個包含所有雜誌字母的字串,如果贖金票據可以從雜誌中構建,則寫一個函式將返回true;否則,它將返回false。雜誌字串中的每個字母只能在贖金票據中使用一次。例如:

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

注意:您可以假設兩個字串僅包含小寫字母。

本次解題使用的開發工具是eclipse,jdk使用的版本是1.8,環境是win7 64位系統,使用Java語言編寫和測試。

02 第一種解法

因為只有小寫字母,可以將magazine所使用到的字元存入一個長度為26的陣列,然後再去遍歷ransomNote所使用到的字元,只要陣列中某一位元素小於0,則返回false。

此解法的時間複雜度是O(n),空間複雜度是O(1)。

public boolean canConstruct(String ransomNote, String magazine) {
    int[] arr = new int[26];
    for (int i=0; i<magazine.length(); i++) {
        arr[magazine.charAt(i)-'a']++;
    }
    for (int j=0; j<ransomNote.length(); j++) {
        if (--arr[ransomNote.charAt(j)-'a'] < 0) {
            return false;
        }
    }
    return true;
}


03 第二種解法

思路和第一種解法一樣,只不過是將傳入的兩個字串先轉換成字元陣列而已。

此解法的時間複雜度是O(n),空間複雜度是O(n)。

public boolean canConstruct2(String ransomNote, String magazine) {
    int[] arr = new int[26];
    char[] note = ransomNote.toCharArray();
    char[] maz = magazine.toCharArray();
    for (int i=0; i<maz.length; i++) {
        arr[maz[i]-'a']++;
    }
    for (int j=0; j<note.length; j++) {
        if (arr[note[j]-'a']-- == 0) {
            return false;
        }
    }
    return true;
}


04 第三種解法

使用HashMap,先將magazine所使用的字元以及出現次數分別作為key和value存入其中,然後遍歷ransomNote的字元,如果其當前字元在map中存在,並且其value值在減1後依然大於等於0,那麼將此字元所對應的value值減1,反之直接返回false。

此解法因為用到了HashMap的contains方法,因此時間複雜度最好情況是O(n),最壞情況是O(n^2),空間複雜度是O(n)。

public boolean canConstruct3(String ransomNote, String magazine) {
    Map<Character, Integer> map = new HashMap<Character, Integer>();
    for (int i=0; i<magazine.length(); i++) {
        char c = magazine.charAt(i);
        map.put(c, map.getOrDefault(c, 0)+1);
    }
    for (int j=0; j<ransomNote.length(); j++) {
        char c = ransomNote.charAt(j);
        if (map.containsKey(c) && map.get(c)-1 >= 0) {
            map.put(c, map.get(c)-1);
        } else {
            return false;
        }
    }
    return true;
}


05 第四種解法

依舊是使用HashMap,但是將第三種解法裡面的兩個迴圈壓縮到一個迴圈裡。迴圈遍歷的物件依舊是ransomNote,獲取當前字元c,同時定義一個變數pos,先判斷c是否存在於map中,如果c存在於map中,則獲取其對應的value並加1,再重新賦值給pos,如果pos大於magazine的長度,直接返回false。

接著重新獲取pos的值,等於當前字元在magazine所在的索引(從pos位開始查詢),如果pos等於-1,說明當前在ransomNote使用的字元不存在於magazine中,直接返回false,如果pos不等於-1,則將ransomNote的當前字元作為key,該字元在magazine中出現的pos為value存入map中。

此解法因為用到了HashMap的contains方法,因此時間複雜度最好情況是O(n),最壞情況是O(n^2),空間複雜度是O(1)。

public boolean canConstruct4(String ransomNote, String magazine) {
    Map<Character, Integer> map = new HashMap<Character, Integer>();
    for (char c : ransomNote.toCharArray()) {
        int pos = 0;
        if (map.containsKey(c)) {
            pos = map.get(c) + 1;
            if (pos >= magazine.length()) {
                return false;
            }
        }
        pos = magazine.indexOf(c, pos);
        if (pos == -1) {
            return false;
        }   
        map.put(c, pos);
    }
    return true;
}


06 小結

演算法專題目前已連續日更超過兩個月,演算法題文章80+篇,公眾號對話方塊回覆【資料結構與演算法】、【演算法】、【資料結構】中的任一關鍵詞,獲取系列文章合集。

以上就是全部內容,如果大家有什麼好的解法思路、建議或者其他問題,可以下方留言交流,點贊、留言、轉發就是對我最大的回報和支援!