1. 程式人生 > >判斷兩個字串是否包含相同的字元(但是允許順序不一樣)

判斷兩個字串是否包含相同的字元(但是允許順序不一樣)

ABCC 在這裡equals CBAC

先比較字串長度就不說了

最笨拙的方法,遍歷A字串,然後再去遍歷B字串, 開一個新陣列標記B上某位是否已匹配過。——O(n^2)

好一點的思路走向

字串其實就是char陣列,每一位的字元其實都是數字

所以“ABCC”是這樣的

一個int陣列。

不過我們不會真的轉化成int陣列,這樣效率不高, 即取即用即可。

所以現在的任務變成了:確認兩個int陣列內包含的數字的種類和 個數是否相等。

這才是問題本來的樣子

所以現在是排下序,排好序後一位位比過去嗎?

這成本太大了。。。

所以我們需要統計每個數字出現的次數

然後大家比一下就好了

再具體 點呢?

65 66 67 67

67 66 65 67

第一行的屬性

65 1

66 1

67 2

第二行的屬性

65 1

66 1

67 2

我們是如何 收集資料的呢?

我們怎麼知道他們是匹配的呢?

我一開始的想法是SparseArray,但是其保持增序的時候需要System.arrayCopy。用連結串列的話,查詢又太過複雜

所以這裡需要一張對映表

我們需要一個新的陣列,可以覆蓋到char 可能的每一個數字

然後下標代表了那個數,下標對應的值對應了那個數出現的次數。

還需要一個新的陣列,所有出現過的值的集合,比如65 66 67 67最後就會收整合65 66 67

之後我們會遍歷這個65 66 67 到對映表中去查,如果 查到不一致的資料了,就失敗了(兩個陣列如果收集的不一致,也不行)

所以最後梳理一下整體的邏輯

兩個 預備陣列

1.對映陣列(這個取值範圍我就有點不太知道了,不過不太重要)

2.出現數組

我們遍歷第一個String,拿到單個char,拿到單個int,給對映陣列對應的位置 上+1,同時如果之前是0,那麼就把這個int也加到出現數組裡取,反之,不加

遍歷第二個陣列的時候,char,int,對映陣列上對應的位置 不是0,就在對應位上的值-1。如果對應位置上 發現是0,就代表沒出現過這個數,或者當前這個陣列,這個值多了一個。 最後再根據出現數組到 對映數組裡去找對應位,看看 是不是都為0了, 如果是,那麼就成功了。

有沒有更牛逼的方法?

我也就是一個猜想。因為我發現String的hashcode特別 神奇,他是怎麼確保兩個String各個位上的字元都相等,僅僅從hashcode 就可以判斷出來呢?因為完全 可能有其他String不一樣的,但是生成的值是一樣的。

所以可以 得出結論:當前元素在陣列中是第幾個+當前元素的字元char的值——組成——>這個位上的代表值。同時累計的值是無法以另外形式拼湊出來的

看看它的原始碼

public int hashCode() {
    int h = hash;
    final int len = length();
    if (h == 0 && len > 0) {
        for (int i = 0; i < len; i++) {
            h = 31 * h + charAt(i);
        }
        hash = h;
    }
    return h;
}

hash預設是0

 每次遍歷一位的時候, 都會把當前的hash值,乘以31, 加上當前位上的字元的ascii值。這似乎能保持其獨一無二? 為什麼?

如果不考慮int溢位的 話,每次乘以31都會上升一個量級,這區分了每一位,同時結合了charAt(i),所以這真的是很難拼湊出來的。(這個東西俺一時半會真的考慮不明白,先簡略這麼寫吧)

同時溢位後,int很有可能會變成負數,所以會一直處於正向溢位,反向溢位的過程中。

反正這個hash 演算法就是很牛逼,不可逆,還具有唯一性!

怎麼借鑑到我們這個情形來呢?

我們 這個情形的掛鉤點無關 位置了,有關於數字的大小和個數,並且不會被其他形式湊出來。

所以處理相同數字的時候,處理邏輯應該是相同的。

我們只需要讓每個數字都有獨一無二的值即可。

然後就沒思路啦。。。哈哈。。。