LeetCode 1239 Maximum Length of a Concatenated String with Unique Characters

Last updated on a few seconds ago

題目連結


❗️ 題意

給定一個字串陣列 $arr$,請你從裡面取出一些字串並將其連接起來,要保證不能出現重複的字元,請輸出所有可能的結果中長度最長為何?

  • Input: $arr = $ [“un”, “iq”,“ue”]

  • Output: $4$

    • “ ”, “un”, “iq”, “ue”, “uniq”, “ique”
    • 長度最長的為 “uniq” 與 “ique”,兩者皆為4
  • Constraints:

    • $1 \leq arr.length \leq 16$
    • $1 \leq arr[i].length \leq 26$
      • $arr[i]$ contains only lowercase English letters.

✔️ 題解

對於此題,由於其陣列長度與其中的字串長度皆不大,因此我們可以很直覺的想到或許可以透過枚舉的方式來解決,因此我在一開始是使用bitmask來枚舉,假設我們現在有一個長度是4的陣列,而bitmask現在是1011,就代表我們要拿第一個,第三個,第四個來計算其連接起來後的結果,而我們只需要透過枚舉0000 ~ 1111,也就是16(1<<4)種情況,就可以將所有可能的情況皆枚舉出來,這種做法由於是將所有可能皆嘗試一次,因此只適用於輸入的陣列不要太大的情況,以此題來說陣列大小最大只有16而已,因此此做法是可以成功AC的,但其效率並不好。

因此我們可以進一步思考,其實很多結果根本不需要嘗試,假設1100就已經違反規定,那其他的例如1101, 1110, 1111根本沒有試的必要,因此我們可以使用 Backtracking 的方式,只對還沒有違反規定的結果來去枚舉下一步,透過這種剪枝的方式,就能大幅度的減少所需要枚舉的次數。


💻 程式碼

  • Bit Mask

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    // 570 ms, AC
    class Solution {
    public:
    vector<string>now;
    int used[30];
    int ans;
    int check(){
    bool alpha[30] = {0};
    int tot = 0;
    for(auto st: now){
    for(auto s: st){
    if(alpha[s - 'a'] == true){
    return -1;
    }
    alpha[s - 'a'] = true;
    tot++;
    }
    }
    return tot;
    }
    int maxLength(vector<string>& arr) {
    for(int i = 0; i < (1 << arr.size()); i++){
    now.clear();
    for(int j = 0; j < arr.size(); j++){
    if((i >> j) & 1){
    now.emplace_back(arr[j]);
    }
    }
    ans = max(ans, check());
    }
    return ans;
    }
    };
  • Backtracking

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    // 21ms, AC
    class Solution {
    public:
    vector<string>now;
    int used[30];
    int ans;
    int check(){
    bool alpha[30] = {0};
    int tot = 0;
    for(auto st: now){
    for(auto s: st){
    if(alpha[s - 'a'] == true){
    return -1;
    }
    alpha[s - 'a'] = true;
    tot++;
    }
    }
    return tot;
    }
    void dfs(int idx, vector<string>& arr){
    for(int i = idx + 1; i < arr.size(); i++){
    if(!used[i]){
    now.emplace_back(arr[i]);
    int chk = check();
    if(chk != -1){
    used[i] = true;
    ans = max(ans, chk);
    dfs(i, arr);
    }
    now.pop_back();
    used[i] = false;
    }
    }
    }

    int maxLength(vector<string>& arr) {
    dfs(-1, arr);
    return ans;
    }
    };

    Runtime: 21 ms, faster than 72.91% of C++ online submissions


🧠 心得

我覺得的我的 check function並沒有寫好, 因為我每次計算時都要重新計算一次長度,但其實不需要這樣做,我們可以維護一組global的陣列,存著目前已使用的字元(a~z),之後計算時只要針對目前要加入的字串去增加或減少此陣列即可,但我好懶就沒有改了XD



LeetCode 1239 Maximum Length of a Concatenated String with Unique Characters
http://example.com/2024/01/23/20240123/
Author
Hank Hsu
Posted on
January 23, 2024
Licensed under