1. 程式人生 > 其它 >力扣-面試題刷題第一天

力扣-面試題刷題第一天

01.01. 判定字元是否唯一 01.02. 判定是否互為字元重排

01.01. 判定字元是否唯一

1、題目

實現一個演算法,確定一個字串 s 的所有字元是否全都不同。

2、初步作答

2.1 思路(錯誤)

作為從C轉過來的 java 選手,做題目第一時間想到的是利用兩重 for 迴圈判斷字串是否相同。

2.2 做法(錯誤)

使用 for 迴圈遍歷字串S(這裡把字串當成了陣列去操作,實操太少,自己太笨),再巢狀一層 for 迴圈遍歷S,遍歷過程中如果遇到相同字元,就返回 false ;迴圈結束,如果全部遍歷結束沒有返回 false ,那麼就返回 true 。

2.3 程式碼(錯誤)

錯誤解法

class Solution {
    public boolean isUnique(String astr) {
        if(astr == null){
            return true;
        }
        for(int i = 0;i < s.length;i++){
            for(int j = i+1;j < s.length;j++){
                if(astr[i] == astr[j]){
                    return false;
                }
            }
        }
        return true;
    }
}
  • 這裡是錯誤思路的解法,當然就是錯誤解法啦。

2.4 思考

刷題經歷太少導致學過的資料結構演算法不知道該怎麼使用,只會簡單的迴圈結構疊加(弊端顯現啊,屬於是)。同時,字串不是陣列,這簡直就是語文當英語看,從頭錯到尾。

3、題目解析

3.1 思路說明

理解到自己的錯誤就去推翻之前的錯誤重新再來,那在這裡我們還需要多考慮幾種情況。

  • 字串是否為空,空字串所有字元肯定全部不相同,直接返回 true;

  • 字串中字元的範圍是什麼?

    • 1.如果是26個英文字母,就有兩種情況需要討論

      • (1) 只能是小寫或大寫字母

        • ① 字串長度大於26直接返回 false;
        • ② 字串長度小於26時,定義一個大小為26的全0陣列。遍歷字串,以'a'=0~'z'=26或'A'=0~'Z'=26 為陣列下標,每個字元出現一次相應的陣列位加1,如果陣列中出現大於1的數時,返回false;如果遍歷結束之後,陣列所有元素都是0或1,則返回 true。
        • 備註:這裡使用兩步判斷是為了節省運算時間和空間消耗,如果字串長度大於26,就不用開闢一個數組空間,同時節省了判斷的時間消耗。
      • (2) 大小寫字母都可以

        • ① 字串長度大於52直接返回 false;
        • ② 字串長度小於52時,定義一個大小為52的全0陣列。遍歷字串,以'a'=0~'z'=26並且'A'=27~'Z'=52 為陣列下標,每個字元出現一次相應的陣列位加1,如果陣列中出現大於1的數時,返回false;如果遍歷結束之後,陣列所有元素都是0或1,則返回 true。
    • 2.如果是ASCII碼,那麼總共範圍就是128

    • 3.如果是Unicode,沒有字元要求,那麼就老老實實排序再判斷

  • 本題也可以直接使用字串索引查詢的方法來判斷 ( S.charAt() )

  • 題目說明不使用額外的資料結構演算法,那麼這道題最本質的還是使用位運算(不太會位運算,敲,這就去學習一下)

3.2 程式碼

3.2.1 使用HashMap

class Solution {
    public boolean isUnique(String astr) {
        if(astr == null){
            return true;
        }
      Map<Character,Integer> map = new HashMap<>();
        for(int i = 0; i< astr.length();i++){
            if(map.containsKey(astr.charAt(i))){
                return false;
            }
            map.put(astr.charAt(i),i);
        }
        return true;
    }
}

3.2.2 使用位運算

class Solution {
    public boolean isUnique(String astr) {
     	int mark = 0;
        for (int i = 0; i < astr.length() ; i++) {
            //移動距離
            int move = (int)astr.charAt(i) - 'a';
           	if ((mark & (1 << move) )!=0){
               	return false;
           	}else {
               	mark |=(1 << move);
           	}
        }
        return true;
}

3.3.3 使用索引比較的方法(初步思路優化)

class Solution {
    public boolean isUnique(String astr) {
        if(astr == null){
            return true;
        }
        for(int i = 0;i < astr.length();i++){
            for(int j = i+1;j < astr.length();j++){
                if(astr.charAt(i) == astr.charAt(j)){
                    return false;
                }
            }
        }
        return true;
    }
}

01.02. 判定是否互為字元重排

1、題目

給定兩個字串 s1s2,請編寫一個程式,確定其中一個字串的字元重新排列後,能否變成另一個字串。

2、初步作答

2.1 思路

一個字串重新排列,僅是字元順序變化,字串長度不變,s1 和 s2 長度應一致。排列過程中要記錄字串中字元是否已經使用,使用過的字元不可二次使用。最終,所有字元全部使用,則字串重排成功。

2.2 做法

  • s2 如果由 s1 重新排列,那麼兩個字串長度一定相同。所以,如果字串長度不同,直接返回false;
  • 新建一個數組,記錄字串中字元使用情況;
  • 我們這裡使用 for 迴圈遍歷 s1 中每一個字元,如果字元排列使用,則相應下標陣列加 1 ;
  • 比較陣列之和與字串長度是否匹配,匹配則返回 true,反之返回 false;

2.3 程式碼

class Solution {
    public boolean CheckPermutation(String s1, String s2) {
        if(s1.length() != s2.length()){
            return false;
        }
        int[] num = new int[s1.length()];
        for(int i = 0;i < s1.length();i++){
            for(int j = 0;j < s2.length();j++){
                if(num[j] == 1){
                    continue;
                }
                if(s1.charAt(i) == s2.charAt(j)){
                    num[j] = 1;
                    break;
                }
            }
        }
        int sum = 0;
        for(int m = 0;m < s1.length();m++){
            sum += num[m];
        }
        if(sum == s1.length()){
            return true;
        }else{
            return false;
        }
    }
}
程式碼執行情況
執行用時:0 ms, 在所有 Java 提交中擊敗了100.00%的使用者
記憶體消耗:39.1 MB, 在所有 Java 提交中擊敗了5.27%的使用者
通過測試用例:23 / 23

2.4 思考

這裡定義了一個數組,導致記憶體消耗偏大。所以程式碼優化上,應著重考慮降低記憶體消耗。

3、題目解析

3.1 字元陣列排序比較

class Solution {
    public boolean CheckPermutation(String s1, String s2) {
        char[] s1char = s1.toCharArray();
        Arrays.sort(s1char);
        char[] s2char = s2.toCharArray();
        Arrays.sort(s2char);
        return new String(s1char).equals(new String(s2char));
    }
}

3.2 雜湊演算法

class Solution {
    public boolean CheckPermutation(String s1, String s2) {
        int len1 = s1.length(), len2 = s2.length();
        if (len1 != len2)
            return false;
        HashMap<Character, Integer> dic = new HashMap<>();
        for (int i = 0; i < len1; i++) {
            dic.put(s1.charAt(i) , dic.getOrDefault(s1.charAt(i), 0) + 1);
        }
        for (int i = 0; i < len2; i++) {
            dic.put(s2.charAt(i) , dic.getOrDefault(s2.charAt(i), 0) - 1);
        }
        for (int val : dic.values()) {
            if (val != 0)
                return false;
        }
        return true;
    }
}
  • 幾種方法在記憶體消耗上都有缺陷,如果有更好的演算法,可以告訴我,謝謝