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

LeetCode 第 216 場周賽

5605.檢查兩個字串陣列是否相等

題目連結:5605.檢查兩個字串陣列是否相等

給你兩個字串陣列 word1word2 。如果兩個陣列表示的字串相同,返回 __true __ ;否則,返回 false

陣列表示的字串 是由陣列中的所有元素 按順序 連線形成的字串。

示例 Sample

示例 1:

**輸入:** word1 = ["ab", "c"], word2 = ["a", "bc"]
**輸出:** true
**解釋:**
word1 表示的字串為 "ab" + "c" -> "abc"
word2 表示的字串為 "a" + "bc" -> "abc"
兩個字串相同,返回 true

示例 2:

**輸入:** word1 = ["a", "cb"], word2 = ["ab", "c"]
**輸出:** false

示例 3:

**輸入:** word1  = ["abc", "d", "defg"], word2 = ["abcddefg"]
**輸出:** true

提示:

  • 1 <= word1.length, word2.length <= 103
  • 1 <= word1[i].length, word2[i].length <= 103
  • 1 <= sum(word1[i].length), sum(word2[i].length) <= 103
  • word1[i]word2[i] 由小寫字母組成

我的題解

class Solution {
 public:
  bool arrayStringsAreEqual(vector<string>& word1, vector<string>& word2) {
    string s1, s2;
    for (auto i : word1) s1 += i;
    for (auto i : word2) s2 += i;
    return s1 == s2;
  }
};

5606.具有給定數值的最小字串

題目連結:5606.具有給定數值的最小字串

小寫字元數值 是它在字母表中的位置(從 1 開始),因此 a 的數值為 1b 的數值為 2c 的數值為
3 ,以此類推。

字串由若干小寫字元組成, 字串的數值 為各字元的數值之和。例如,字串 "abe" 的數值等於 1 + 2 + 5 = 8

給你兩個整數 nk 。返回 長度 等於 n數值 等於 k字典序最小 的字串。

注意,如果字串 x 在字典排序中位於 y 之前,就認為 x 字典序比 y 小,有以下兩種情況:

  • xy 的一個字首;
  • 如果 ix[i] != y[i] 的第一個位置,且 x[i] 在字母表中的位置比 y[i] 靠前。

示例 Sample

示例 1:

**輸入:** n = 3, k = 27
**輸出:** "aay"
**解釋:** 字串的數值為 1 + 1 + 25 = 27,它是數值滿足要求且長度等於 3 字典序最小的字串。

示例 2:

**輸入:** n = 5, k = 73
**輸出:** "aaszz"

提示:

  • 1 <= n <= 105
  • n <= k <= 26 * n

我的題解

class Solution {
 public:
  string getSmallestString(int n, int k) {
    k -= n;
    vector<int> a(n);
    for (int i = 0; i < n; i++) a[i] = 0;
    for (int i = n - 1, t; i >= 0 && k; i--) {
      t = min(25, k);
      a[i] += t, k -= t;
    }
    string s;
    for (int i = 0; i < n; ++i) s += a[i] + 'a';
    return s;
  }
};

5607.生成平衡陣列的方案數

題目連結:5607.生成平衡陣列的方案數

給你一個整數陣列 nums 。你需要選擇 恰好 一個下標(下標從 0
開始)並刪除對應的元素。請注意剩下元素的下標可能會因為刪除操作而發生改變。

比方說,如果 nums = [6,1,7,4,1] ,那麼:

  • 選擇刪除下標 1 ,剩下的陣列為 nums = [6,7,4,1]
  • 選擇刪除下標 2 ,剩下的陣列為 nums = [6,1,4,1]
  • 選擇刪除下標 4 ,剩下的陣列為 nums = [6,1,7,4]

如果一個數組滿足奇數下標元素的和與偶數下標元素的和相等,該陣列就是一個 平衡陣列

請你返回刪除操作後,剩下的陣列 __nums __ 是 平衡陣列方案數

示例 Sample

示例 1:

**輸入:** nums = [2,1,6,4]
**輸出:** 1
**解釋:**
刪除下標 0 :[1,6,4] -> 偶數元素下標為:1 + 4 = 5 。奇數元素下標為:6 。不平衡。
刪除下標 1 :[2,6,4] -> 偶數元素下標為:2 + 4 = 6 。奇數元素下標為:6 。平衡。
刪除下標 2 :[2,1,4] -> 偶數元素下標為:2 + 4 = 6 。奇數元素下標為:1 。不平衡。
刪除下標 3 :[2,1,6] -> 偶數元素下標為:2 + 6 = 8 。奇數元素下標為:1 。不平衡。
只有一種讓剩餘陣列成為平衡陣列的方案。

示例 2:

**輸入:** nums = [1,1,1]
**輸出:** 3
**解釋:** 你可以刪除任意元素,剩餘陣列都是平衡陣列。

示例 3:

**輸入:** nums = [1,2,3]
**輸出:** 0
**解釋:** 不管刪除哪個元素,剩下陣列都不是平衡陣列。

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 104

我的題解

\(s_i\) 表示從 i 開始的間隔為 1 的序列和,那麼刪掉第 k 個,有

  • k 為奇數
    • 偶數項和為 \(s_0 - s_{k + 1} + s_{k + 2}\)
    • 奇數項和為 \(s_1-s_k+s_{k+1}\);
  • k 為偶數
    • 偶數項和為 \(s_0-s_k+s_{k+1}\)
    • 奇數項和為 \(s_1 - s_{k+1}+s_{k+2}\)
class Solution {
 public:
  bool chk(int k, const vector<int>& s) {
    int x, y;
    if (k & 1) {
      x = s[0] - s[k + 1] + s[k + 2];
      y = s[1] - s[k] + s[k + 1];
    } else {
      x = s[0] - s[k] + s[k + 1];
      y = s[1] - s[k + 1] + s[k + 2];
    }
    return x == y;
  }

  int waysToMakeFair(vector<int>& nums) {
    const int n = nums.size();
    vector<int> s(n + 2, 0);
    for (int i = n - 1; i >= 0; i--) {
      s[i] = (i + 2 < n ? s[i + 2] : 0) + nums[i];
    }
    int ans(0);
    for (int i = 0; i < n; ++i) {
      if (chk(i, s)) ans++;
    }
    return ans;
  }
};

5608.完成所有任務的最少初始能量

題目連結:5608.完成所有任務的最少初始能量

給你一個任務陣列 tasks ,其中 tasks[i] = [actuali, minimumi]

  • actuali 是完成第 i 個任務 需要耗費 的實際能量。
  • minimumi 是開始第 i 個任務前需要達到的最低能量。

比方說,如果任務為 [10, 12] 且你當前的能量為 11 ,那麼你不能開始這個任務。如果你當前的能量為 13
,你可以完成這個任務,且完成它後剩餘能量為 3

你可以按照 任意順序 完成任務。

請你返回完成所有任務的 最少 初始能量。

示例 Sample

示例 1:

**輸入:** tasks = [[1,2],[2,4],[4,8]]
**輸出:** 8
**解釋:**
一開始有 8 能量,我們按照如下順序完成任務:
    - 完成第 3 個任務,剩餘能量為 8 - 4 = 4 。
    - 完成第 2 個任務,剩餘能量為 4 - 2 = 2 。
    - 完成第 1 個任務,剩餘能量為 2 - 1 = 1 。
注意到儘管我們有能量剩餘,但是如果一開始只有 7 能量是不能完成所有任務的,因為我們無法開始第 3 個任務。

示例 2:

**輸入:** tasks = [[1,3],[2,4],[10,11],[10,12],[8,9]]
**輸出:** 32
**解釋:**
一開始有 32 能量,我們按照如下順序完成任務:
    - 完成第 1 個任務,剩餘能量為 32 - 1 = 31 。
    - 完成第 2 個任務,剩餘能量為 31 - 2 = 29 。
    - 完成第 3 個任務,剩餘能量為 29 - 10 = 19 。
    - 完成第 4 個任務,剩餘能量為 19 - 10 = 9 。
    - 完成第 5 個任務,剩餘能量為 9 - 8 = 1 。

示例 3:

**輸入:** tasks = [[1,7],[2,8],[3,9],[4,10],[5,11],[6,12]]
**輸出:** 27
**解釋:**
一開始有 27 能量,我們按照如下順序完成任務:
    - 完成第 5 個任務,剩餘能量為 27 - 5 = 22 。
    - 完成第 2 個任務,剩餘能量為 22 - 2 = 20 。
    - 完成第 3 個任務,剩餘能量為 20 - 3 = 17 。
    - 完成第 1 個任務,剩餘能量為 17 - 1 = 16 。
    - 完成第 4 個任務,剩餘能量為 16 - 4 = 12 。
    - 完成第 6 個任務,剩餘能量為 12 - 6 = 6 。

提示:

  • 1 <= tasks.length <= 105
  • 1 <= actual​i <= minimumi <= 104

我的題解

按照差值貪心即可。(大膽猜的結論,下面的內容參考的 [zerotrac的題解)ORZ

不妨設答案為 \(ans\) ,完成任務順序為 \((a_0,m_0),(a_1,m_1),...(a_{n-1},m_{n-1})\),那麼

\[\begin{aligned} ans \ge m_0 \\ ans -a_0 \ge m_1 \\ ans -a_0-a_1 \ge m_2 \\ ...\\ ans - \sum_0^{n-1}a_i \ge m_{n-1} \end{aligned} \]

移動不等式,有

\[\begin{aligned} ans &\ge m_0 \\ ans &\ge a_0 + m_1 \\ ans &\ge a_0+a_1+m_2 \\ ...\\ ans &\ge m_{n-1} +\sum_0^{n-1}a_i \end{aligned} \]

那麼如何最小化這個最大值?假設我們交換了任務 \((a_i, m_i)\) 以及 \((a_{i+1},m_{i+1})\) ,那麼只有交換前:

\[\begin{aligned} p &\geq a_0+a_1+\cdots+a_{i-1}+m_i = P(i,0) \\ p &\geq a_0+a_1+\cdots+a_{i-1}+a_i+m_{i+1} = P(i,1) \end{aligned} \]

以及交換後:

\[\begin{aligned} p &\geq a_0+a_1+\cdots+a_{i-1}+m_{i+1} = P'(i,0) \\ p &\geq a_0+a_1+\cdots+a_{i-1}+a_{i+1}+m_i = P'(i,1) \end{aligned} \]

那麼可以通過交換來進行鬆弛(優化當前答案)。交換前的最大值為 \(\max \{ P(i,0),P(i,1) \}\) ,交換後的最大值為 \(\max \big\{ P'(i,0),P'(i,1) \big\}\) 。由於 \(P(i,0) < P'(i,1)\) 以及 \(P'(i,0) < P(i,1)\) 恆成立(無論順序如何,能量消耗都是遞增的),因此交換的條件

\[\begin{aligned} max \{ P(i,0),P(i,1) \} & \gt max \{P'(i,0),P'(i,1)\} \\ a_i+m_{i+1}& \gt a_{i+1}+m_i \\ a_i-m_i &\gt a_{i+1}-m_{i+1} \end{aligned} \]

綜上,按照差值排序貪心即可。

class Solution {
 public:
  int minimumEffort(vector<vector<int>>& tasks) {
    const int n = tasks.size();
    sort(tasks.begin(), tasks.end(), [&](vector<int>& a, vector<int>& b) {
      if (a[1] - a[0] != b[1] - b[0]) return a[1] - a[0] < b[1] - b[0];
      return a[1] < b[1];
    });

    int ans(0), d(0);
    for (int i = 0; i < n; ++i) {
      ans += tasks[i][0];
      if (ans + d < tasks[i][1]) d += tasks[i][1] - ans;
    }
    return ans + d;
  }
};