判斷字串是否唯一

怀念-2018發表於2024-04-02

演算法1:用於判斷一個字串的字元是否都是唯一的,即沒有重複的字元。

解決思路:首先將輸入的字串轉換為字元陣列,然後對字元陣列進行排序。之後,使用一個while迴圈遍歷排序後的字元陣列,如果發現有任何兩個相鄰的字元相同,則返回false,表示字串中有重複的字元。如果迴圈結束後都沒有發現相鄰的字元相同,則返回true,表示字串中的字元都是唯一的。

程式碼示例:

 public boolean isUnique(String astr) {
        char[] chars = astr.toCharArray();
        Arrays.sort(chars);
        int i=0;
        while(i<chars.length-1){
            if(chars[i]==chars[i+1]){
                return false;
            }
            i++;
        }
        return true;
    }

上面潛在問題與風險:

字元編碼問題:此方法假設所有字元都可以使用char型別處理,這對於大多數ASCII和Unicode字元是有效的。但是,如果處理包含如中文、希伯來文等複雜指令碼的字串時,單個字元可能需要多個char來表示(Java中的String和char基於UTF-16編碼,對於代理對這種情況需要特殊處理)。這可能不是您想要的行為,尤其是在處理全球化的應用程式時。
效能效率問題:該方法對字串進行排序,這在字串非常長時可能非常耗時。對於判斷字串是否唯一的目的,排序並不是最高效的方法,因為它的時間複雜度是O(nlogn)。
空間複雜度問題:轉換字串為字元陣列並進行排序將需要額外的O(n)空間複雜度,這在某些記憶體受限的場景下可能不是最佳選擇。
異常處理:方法中沒有對輸入引數astr進行空值檢查。雖然Java中對空字串進行排序不會丟擲異常,但如果業務邏輯不允許空字串的存在,應當顯式檢查。
最佳化方向
使用HashSet:一個更高效的方法是使用HashSet。HashSet是一個無序、不重複元素的集合,它的新增操作的時間複雜度接近O(1)。可以透過遍歷字串的每個字元,嘗試將它們新增到HashSet中來判斷字元是否重複。如果字元重複,HashSet會拒絕新增,並立即返回false。這種方法的時間複雜度接近O(n),且不需要額外排序,更高效。
檢查字串長度:可以透過直接檢查字串的長度和字符集的大小來快速判斷字串是否包含重複字元。例如,如果字串長度大於字符集的大小(考慮Unicode,這個字符集大小是固定的,即Character.MAX_VALUE),則一定存在重複字元,可以直接返回false。這種方法可以提前終止一些不必要的檢查,尤其是在字串很長時。
不使用額外空間:如果空間複雜度是一個重要考慮因素,可以透過遍歷字串,使用一個長度為Character.MAX_VALUE的boolean陣列來標記字元是否出現過。這樣可以將空間複雜度降低到O(1),但會稍微犧牲一些時間複雜度,因為需要額外的邏輯來處理Unicode代理對。
程式碼可讀性:當前方法的實現邏輯較為間接(透過排序來尋找重複),對於未深入瞭解的讀者可能不夠直觀。使用HashSet或其他直接演算法可以提高程式碼的可讀性和可維護性。
安全性和邊界條件
安全性:此方法不涉及網路、檔案訪問或其他外部資源,因此從傳統意義上講是安全的。但是,它依賴於Java String和字元陣列的實現,應確保使用的Java環境沒有相關安全漏洞。
邊界條件:應當檢查輸入引數是否為null,避免潛在的NullPointerException。同時,空字串("")應當被認為是不包含重複字元的,這一點當前實現處理得當。
以下是相應的程式碼最佳化。請注意,由於涉及的修改較為複雜,一些細節可能需要進一步調整。

根據上述建議,可以使用HashSet來最佳化原始碼,不僅提高效能,同時增強程式碼的可讀性和可維護性。以下是使用HashSet重構後的程式碼:

 1 public class StringUniqueChecker {
 2     /**
 3      * 用於判斷一個字串的字元是否都是唯一的,即沒有重複的字元。
 4      * 使用HashSet來檢查字元是否重複,HashSet的add方法會自動拒絕重複的元素。
 5      * @param astr 輸入的字串
 6      * @return 如果字串中的字元都是唯一的,則返回true;否則,返回false。
 7      */
 8     public boolean isUnique(String astr) {
 9         // 檢查輸入是否為null或空字串
10         if (astr == null || astr.isEmpty()) {
11             return true;
12         }
13 
14         HashSet<Character> set = new HashSet<>();
15         for (int i = 0; i < astr.length(); i++) {
16             char c = astr.charAt(i);
17             // 如果set中已經包含了當前字元,則說明有重複字元
18             if (set.contains(c)) {
19                 return false;
20             }
21             set.add(c);
22         }
23         return true;
24     }
25 }

    

相關文章