leetcode周賽2111. 使陣列 K 遞增的最少操作次數(貪心 二分)
連結:https://leetcode-cn.com/problems/minimum-operations-to-make-the-array-k-increasing/
題目
給你一個下標從 0開始包含 n個正整數的陣列arr,和一個正整數k。
如果對於每個滿足k <= i <= n-1的下標i,都有arr[i-k] <= arr[i],那麼我們稱arr是 K遞增 的。
比方說,arr = [4, 1, 5, 2, 6, 2]對於k = 2是 K 遞增的,因為:
arr[0] <= arr[2] (4 <= 5)
arr[1] <= arr[3] (1 <= 2)
arr[2] <= arr[4] (5 <= 6)
arr[3] <= arr[5] (2 <= 2)
但是,相同的陣列arr對於k = 1不是 K 遞增的(因為arr[0] > arr[1]),對於k = 3也不是 K 遞增的(因為arr[0] > arr[3])。
每一次 操作中,你可以選擇一個下標i 並將arr[i] 改成任意正整數。
請你返回對於給定的 k,使陣列變成 K 遞增的 最少操作次數。
用例
示例 1:
輸入:arr = [5,4,3,2,1], k = 1
輸出:4
解釋:
對於 k = 1 ,陣列最終必須變成非遞減的。
可行的 K 遞增結果陣列為 [5,6,7,8,9],[1,1,1,1,1],[2,2,3,4,4] 。它們都需要 4 次操作。
次優解是將陣列變成比方說 [6,7,8,9,10] ,因為需要 5 次操作。
顯然我們無法使用少於 4 次操作將陣列變成 K 遞增的。
示例 2:
輸入:arr = [4,1,5,2,6,2], k = 2
輸出:0
解釋:
這是題目描述中的例子。
對於每個滿足 2 <= i <= 5 的下標 i ,有 arr[i-2] <= arr[i] 。
由於給定陣列已經是 K 遞增的,我們不需要進行任何操作。
示例 3:
輸入:arr = [4,1,5,2,6,2], k = 3
輸出:2
解釋:
下標 3 和 5 是僅有的 3 <= i <= 5 且不滿足 arr[i-3] <= arr[i] 的下標。
將陣列變成 K 遞增的方法之一是將 arr[3] 變為 4 ,且將 arr[5] 變成 5 。
陣列變為 [4,1,5,4,6,5] 。
可能有其他方法將陣列變為 K 遞增的,但沒有任何一種方法需要的操作次數小於 2 次。
提示:
1 <= arr.length <= 105
1 <= arr[i], k <= arr.length
思路
將陣列變為遞增陣列的最小運算元,即為求出陣列的最長遞增陣列,連結:
但是由於陣列長度為10e5,所以leetcode300中的dp演算法o(n^2)會超時,故只能選用貪心二分查詢
針對每k個數組 維護一個數組,如果當前數大於陣列的最後一個數,則放入陣列,如果小於,則找到陣列中第一個大於該數的數,進行替換
class Solution {
public:
int kIncreasing(vector<int>& arr, int k) {
int ret = 0;
int n = arr.size();
vector<int> v;
v.reserve((n + k - 1) / k);
for (int i = 0; i < k; ++i) {
v.clear();
v.push_back(arr[i]);
for (int j = i + k; j < n; j += k) {
if (arr[j] >= v.back()) {
v.push_back(arr[j]);
} else {
int pos = upper_bound(v.begin(), v.end(), arr[j]) - v.begin();
v[pos] = arr[j];
ret++;
}
}
}
return ret;
}
};