1. 程式人生 > 實用技巧 >LeetCode 第 199 場周賽

LeetCode 第 199 場周賽

第4題DP有點意思

5472.重新排列字串

題目連結:5472.重新排列字串

給你一個字串 s 和一個 長度相同 的整數陣列 indices

請你重新排列字串 s ,其中第 i 個字元需要移動到 indices[i] 指示的位置。

返回重新排列後的字串。

示例 Sample

示例 1:

**輸入:** s = "codeleet", indices = [4,5,6,7,0,2,1,3]
**輸出:** "leetcode"
**解釋:** 如圖所示,"codeleet" 重新排列後變為 "leetcode" 。

示例 2:

**輸入:** s = "abc", indices = [0,1,2]
**輸出:** "abc"
**解釋:** 重新排列後,每個字元都還留在原來的位置上。

示例 3:

**輸入:** s = "aiohn", indices = [3,1,4,2,0]
**輸出:** "nihao"

示例 4:

**輸入:** s = "aaiougrt", indices = [4,0,2,6,7,3,1,5]
**輸出:** "arigatou"

示例 5:

**輸入:** s = "art", indices = [1,0,2]
**輸出:** "rat"

提示:

  • s.length == indices.length == n
  • 1 <= n <= 100
  • s 僅包含小寫英文字母。
  • 0 <= indices[i] < n
  • indices 的所有的值都是唯一的(也就是說,indices 是整數 0n - 1 形成的一組排列)。

題解

class Solution {
 public:
  string restoreString(string s, vector<int>& indices) {
    vector<char>ans(s.length());
    for(int i = 0; i < s.length(); i++)
      ans[indices[i]] = s[i];
    s = "";
    for(int i = 0; i < ans.size(); i++)
      s += ans[i];
    return s;
  }
};

5473.燈泡開關 IV

題目連結:5473.燈泡開關 IV

房間中有 n 個燈泡,編號從 0n-1 ,自左向右排成一行。最開始的時候,所有的燈泡都是 著的。

請你設法使得燈泡的開關狀態和 target 描述的狀態一致,其中 target[i] 等於 1i 個燈泡是開著的,等於 0
意味著第 i 個燈是關著的。

有一個開關可以用於翻轉燈泡的狀態,翻轉操作定義如下:

  • 選擇當前配置下的任意一個燈泡(下標為 i
  • 翻轉下標從 in-1 的每個燈泡

翻轉時,如果燈泡的狀態為 0 就變為 1,為 1 就變為 0

返回達成 target 描述的狀態所需的 最少 翻轉次數。

示例 Sample

示例 1:

**輸入:** target = "10111"
**輸出:** 3
**解釋:** 初始配置 "00000".
從第 3 個燈泡(下標為 2)開始翻轉 "00000" -> "00111"
從第 1 個燈泡(下標為 0)開始翻轉 "00111" -> "11000"
從第 2 個燈泡(下標為 1)開始翻轉 "11000" -> "10111"
至少需要翻轉 3 次才能達成 target 描述的狀態

示例 2:

**輸入:** target = "101"
**輸出:** 3
**解釋:** "000" -> "111" -> "100" -> "101".

示例 3:

**輸入:** target = "00000"
**輸出:** 0

示例 4:

**輸入:** target = "001011101"
**輸出:** 5

提示:

  • 1 <= target.length <= 10^5
  • target[i] == '0' 或者 target[i] == '1'

題解

class Solution {
 public:
  int minFlips(string target) {
    int ans(0);
    for(int i = 0, st = 0; i < target.length(); i++) {
      if(target[i] - '0' == st)
        continue;
      st ^= 1, ans++;
    }
    return ans;
  }
};

5474.好葉子節點對的數量

題目連結:5474.好葉子節點對的數量

給你二叉樹的根節點 root 和一個整數 distance

如果二叉樹中兩個 節點之間的 最短路徑長度 小於或者等於 distance ,那它們就可以構成一組 好葉子節點對

返回樹中 好葉子節點對的數量

示例 Sample

示例 1:

**輸入:** root = [1,2,3,null,4], distance = 3
**輸出:** 1
**解釋:** 樹的葉節點是 3 和 4 ,它們之間的最短路徑的長度是 3 。這是唯一的好葉子節點對。

示例 2:

**輸入:** root = [1,2,3,4,5,6,7], distance = 3
**輸出:** 2
**解釋:** 好葉子節點對為 [4,5] 和 [6,7] ,最短路徑長度都是 2 。但是葉子節點對 [4,6] 不滿足要求,因為它們之間的最短路徑長度為 4 。

示例 3:

**輸入:** root = [7,1,4,6,null,5,3,null,null,null,null,null,2], distance = 3
**輸出:** 1
**解釋:** 唯一的好葉子節點對是 [2,5] 。

示例 4:

**輸入:** root = [100], distance = 1
**輸出:** 0

示例 5:

**輸入:** root = [1,1,1], distance = 2
**輸出:** 1

提示:

  • tree 的節點數在 [1, 2^10] 範圍內。
  • 每個節點的值都在 [1, 100] 之間。
  • 1 <= distance <= 10

題解

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
 public:

  vector<int> gao(const TreeNode* root, const int distance, int &ans) {
    if(root == nullptr)
      return {};
    if(root->left == nullptr && root->right == nullptr) {
      return {1};
    }
    vector<int>lch = gao(root->left, distance, ans);
    vector<int>rch = gao(root->right, distance, ans);
    for(int i = 0; i < min(distance, (int)lch.size()); i++) {
      if(lch[i])
        for(int j = 0; j < min(distance, (int)rch.size()); j++) {
          if(i + j + 2 <= distance)
            ans += lch[i] * rch[j];
        }
    }
    vector<int>v(max(lch.size(), rch.size()) + 1);
    for(int i = 0; i < lch.size(); i++)
      v[i + 1] += lch[i];
    for(int i = 0; i < rch.size(); i++)
      v[i + 1] += rch[i];
    return v;
  }

  int countPairs(TreeNode* root, int distance) {
    int ans(0);
    gao(root, distance, ans);
    return ans;
  }
};

5462.壓縮字串 II

題目連結:5462.壓縮字串 II

行程長度編碼
是一種常用的字串壓縮方法,它將連續的相同字元(重複 2 次或更多次)替換為字元和表示字元計數的數字(行程長度)。例如,用此方法壓縮字串
"aabccc" ,將 "aa" 替換為 "a2""ccc" 替換為 "c3"。因此壓縮後的字串變為"a2bc3"` 。

注意,本問題中,壓縮時沒有在單個字元後附加計數 '1'

給你一個字串 s 和一個整數 k 。你需要從字串 s 中刪除最多 k 個字元,以使 s 的行程長度編碼長度最小。

請你返回刪除最多 k 個字元後,s 行程長度編碼的最小長度

示例 Sample

示例 1:

**輸入:** s = "aaabcccd", k = 2
**輸出:** 4
**解釋:** 在不刪除任何內容的情況下,壓縮後的字串是 "a3bc3d" ,長度為 6 。最優的方案是刪除 'b' 和 'd',這樣一來,壓縮後的字串為 "a3c3" ,長度是 4 。

示例 2:

**輸入:** s = "aabbaa", k = 2
**輸出:** 2
**解釋:** 如果刪去兩個 'b' 字元,那麼壓縮後的字串是長度為 2 的 "a4" 。

示例 3:

**輸入:** s = "aaaaaaaaaaa", k = 0
**輸出:** 3
**解釋:** 由於 k 等於 0 ,不能刪去任何字元。壓縮後的字串是 "a11" ,長度為 3 。

提示:

  • 1 <= s.length <= 100
  • 0 <= k <= s.length
  • s 僅包含小寫英文字母

題解

對於前 \(i\) 個位置已經刪除 \(j\) 個,分兩類情況

  1. \(i\) 位置刪除,更新 \(i+1\) 位置刪除 \(j+1\) 個的解
  2. 不刪除,那麼貪心的儘可能保留 s[i] ,向後刪除後繼的 s[l] != s[i],同時更新 f[l][j+del]
class Solution {
 public:
  int getLengthOfOptimalCompression(const string s, const int m) {
    const int n = s.length();
    vector<vector<int>>f(n + 1, vector<int>(m + 1, 0x3f3f3f3f));
    f[0][0] = 0;
    for(int i = 0; i < n; ++i) {
      for(int j = 0; j <= m; ++j) {
        if(j + 1 <= m)
          f[i + 1][j + 1] = min(f[i + 1][j + 1], f[i][j]);
        for(int l = i, d = 0, c = 0; l < n; l++) {
          if(s[l] != s[i])
            d ++;
          else
            c++;
          if(j + d > m)
            break;
          f[l + 1][j + d] = min(f[l + 1][j + d], f[i][j] + 1 + (c > 99 ? 3 : (c > 9 ? 2 : c > 1 ? 1 : 0)));
        }
      }
    }
    return f[n][m];
  }
};