LeetCode第 284 場周賽題解
6031. 找出陣列中的所有 K 近鄰下標
題目描述:給你一個下標從 \(0\) 開始的整數陣列 \(nums\) 和兩個整數 \(key\) 和 \(k\) 。\(k\) 近鄰下標 是 \(nums\) 中的一個下標 \(i\) ,並滿足至少存在一個下標\(j\) 使得 \(|i - j| \leq k\) 且 \(nums[j] == key\) 。
以列表形式返回按 遞增順序 排序的所有 \(k\) 近鄰下標。
思路:考慮到\(n\)很小,直接暴力模擬即可
時間複雜度:\(O(n^2)\)
參考程式碼:
class Solution { public: vector<int> findKDistantIndices(vector<int>& nums, int key, int k) { int n = nums.size(); vector<int>res; for(int i = 0 ; i < n ; ++i){ for(int j = max(0 , i - k) ; j < min(n , i + k + 1) ; ++j){ if(nums[j] != key) continue; res.push_back(i); break; } } return res; } };
5203. 統計可以提取的工件
題目描述:自己讀題
思路:比較明顯的二維字首和,根據題意模擬即可
時間複雜度:\(O(n^2)\)
參考程式碼:
class Solution { public: int digArtifacts(int n, vector<vector<int>>& artifacts, vector<vector<int>>& dig) { vector<vector<int>>grid(n + 1 , vector<int>(n + 1 , 0)); for(auto& vec : dig){ int u = vec[0] + 1, v = vec[1] + 1; grid[u][v] = 1; } for(int i = 1 ; i <= n ; ++i){ for(int j = 1 ; j <= n ; ++j){ grid[i][j] = grid[i][j] + grid[i - 1][j] + grid[i][j - 1] - grid[i - 1][j - 1]; } } int res = 0; for(auto& vec : artifacts){ int a = vec[0] + 1 , b = vec[1] + 1, c = vec[2] + 1, d = vec[3] + 1; int sum = grid[c][d] - grid[c][b - 1] - grid[a - 1][d] + grid[a - 1][b - 1]; if(sum == (c - a + 1) * (d - b + 1)) ++res; } return res; } };
5227. K 次操作後最大化頂端元素
題目描述:給你一個下標從 \(0\) 開始的整數陣列 \(nums\) ,它表示一個 棧 ,其中 \(nums[0]\) 是棧頂的元素。每一次操作中,你可以執行以下操作 之一 :
- 如果棧非空,那麼 刪除 棧頂端的元素。
- 如果存在 \(1\) 個或者多個被刪除的元素,你可以從它們中選擇任何一個,新增 回棧頂,這個元素成為新的棧頂元素。
同時給你一個整數 \(k\) ,它表示你總共需要執行操作的次數。
請你返回 恰好 執行 \(k\) 次操作以後,棧頂元素的 最大值 。如果執行完 \(k\) 次操作以後,棧一定為空,請你返回 \(-1\) 。
思路:根據題意模擬即可,對於當前棧頂數字,若拿起後,剩餘操作次數為奇數或者剩餘操作次數大於\(2\)
時間複雜度:\(O(n)\)
參考程式碼:
class Solution {
public:
int maximumTop(vector<int>& nums, int k) {
int res = -1, n = nums.size();
reverse(nums.begin() , nums.end());
nums.push_back(0);
reverse(nums.begin() , nums.end());
for(int i = 1 ; i <= n ; ++i){
int dx = k - i;
if(dx % 2 == 1) res = max(res , nums[i]);
else if(dx >= 2 && n != 1) res = max(res , nums[i]);
}
if(k < n) res = max(res , nums[k + 1]);
return res;
}
};
6032. 得到要求路徑的最小帶權子圖
題目描述:給定\(n\)個點\(m\)條邊的有向圖,求刪除一些邊之後使得刪邊之後的圖權值和最小,且\(s1,s2\)都可以到達\(dest\)。求最小權值和,若不能滿足條件,返回\(-1\)。
思路:定義\(dist_{i , j}\)表示從\(i\)出發到\(j\)的最短路徑,那麼答案為:
\[\mathop{min}\limits_{i = 0}^{n - 1}\;dist_{s1 , i} + dist_{s2 , i} + dist_{i , dest} \]所以對\(s1,s2\)跑\(Dijkstra\),然後建立反向邊以\(dest\)為起點跑\(Dijkstra\),然後列舉中間點取最小即可。
時間複雜度:\(O(mlogm)\)
參考程式碼:
class Solution {
public:
long long minimumWeight(int n, vector<vector<int>>& edges, int s1, int s2, int dest) {
using PLI = pair<long long, int>;
using PII = pair<int , int>;
vector<vector<PII>>graph(n), regraph(n);
vector<vector<int>>tr(n);
for (auto& edge : edges) {
int u = edge[0], v = edge[1], w = edge[2];
graph[u].push_back({ v , w });
regraph[v].push_back({u , w});
}
const long long MAXN = 0x3f3f3f3f3f3f3fll;
auto Dijkstra = [](vector<vector<PII>>& graph ,vector<long long>& dist, int st, int n) {
dist[st] = 0;
priority_queue<PLI, vector<PLI>, greater<PLI>>heap;
heap.push({ 0 , st });
vector<bool>vis(n, false);
while (!heap.empty()) {
auto [dis, ver] = heap.top();
heap.pop();
if (vis[ver]) continue;
vis[ver] = true;
for (auto&& [v, w] : graph[ver]) {
if (dist[v] > w + dis) {
dist[v] = w + dis;
heap.push({ dist[v] , v });
}
}
}
};
vector<long long>d1(n, MAXN), d2(n , MAXN) , d3(n , MAXN);
Dijkstra(graph , d1 , s1 , n);
Dijkstra(graph , d2 , s2 , n);
Dijkstra(regraph , d3 , dest , n);
if(d3[s1] == MAXN || d3[s2] == MAXN) return -1;
long long res = LLONG_MAX;
for(int i = 0 ; i < n ; ++i){
res = min(res , d1[i] + d2[i] + d3[i]);
}
return res;
}
};