LeetCode #12 雙週賽
5097. 力扣排行榜
題目:設計一個排行榜,滿足插入、前綴和、排序。
分析:數據範圍很小,用不到 logn 的數據結構,直接暴力即可。
用 存編號對應成績,每次查詢暴力排序找前 k 和。
class Leaderboard {
public:
map<int, int> mp;
Leaderboard() {}
void addScore(int playerId, int score) {
mp[playerId] += score;
}
int top(int K) {
vector<int> arr;
for (auto it = mp.begin(); it != mp.end(); it++) {
arr.push_back(it->second);
}
sort(arr.begin(), arr.end());
int ans = 0, pos = arr.size() - 1;
while (K--) {
ans += arr[pos--];
}
return ans;
}
void reset(int playerId) {
mp[playerId] = 0;
}
};
5096. 數組變換
題目:
分析:按題意模擬
class Solution {
public:
vector<int> transformArray(vector<int>& arr) {
int n = arr.size(), flag = 1, p = 1;
vector<int> ans[2];
for (auto x : arr) {
ans[0].push_back(x); ans[1].push_back(x);
}
while (flag) {
flag = 0;
for (int i = 0; i < n; i++) {
if (i == 0 || i == n - 1) {
ans[p][i] = ans[p ^ 1][i];
} else if (ans[p ^ 1][i] > ans[p ^ 1][i - 1] && ans[p ^ 1][i] > ans[p ^ 1][i + 1]) {
ans[p][i] = ans[p ^ 1][i] - 1; flag = 1;
} else if (ans[p ^ 1][i] < ans[p ^ 1][i - 1] && ans[p ^ 1][i] < ans[p ^ 1][i + 1]) {
ans[p][i] = ans[p ^ 1][i] + 1; flag = 1;
} else {
ans[p][i] = ans[p ^ 1][i];
}
}
p ^= 1;
}
return ans[p ^ 1];
}
};
5098. 樹的直徑
題目:求樹的直徑(樹上最長路徑)
分析:經典題目,先建樹,
用 維護以 i 爲根的子樹的深度,(j 爲 i 的兒子)。
求出任意節點 i 子樹深度之後,經過 i 的最長路徑就是最深的兩顆子樹深度相加。
經過點 的最長路徑就是最深的兩顆子樹深度相加。最後答案就是所有點的最大值。
class Solution {
public:
void DP(int* dp, int rt, vector<int>* son, int& ans) {
dp[rt] = 0;
int m1 = 0, m2 = 0;
for (auto x : son[rt]) {
DP(dp, x, son, ans);
if(dp[x] + 1 > m1){
m2 = m1;
m1 = dp[x] + 1;
}else if(dp[x] + 1 > m2){
m2 = dp[x] + 1;
}
}
dp[rt] = m1;
ans = max(ans, m1 + m2);
}
int treeDiameter(vector<vector<int>>& edges) {
vector<int> son[10010];
int dp[10010];
int n = 0, vis[10010], rt, ans = 0;
for (auto x : edges) {
son[x[0]].push_back(x[1]);
n = max(n, max(x[0], x[1]));
vis[x[1]]++;
}
for (int i = 0; i <= n; i++) {
if (!vis[i]) {
rt = i; break;
}
}
DP(dp, rt, son, ans);
return ans;
}
};
5115. 刪除迴文子數組
題目:給一個數組,每次可以刪去迴文子數組,刪去之後右邊的右移。問刪去整個數組所需要的最小操作次數。
分析:明顯區間 dp,用 表示刪去 所需要最小操作數,最終答案就是 。
轉移方程:
當區間兩端點相同時,有:,即兩端點可以跟裏面區間最後一次一起刪。
class Solution {
const int N = 1e2 + 10;
const int INF = 0x3f3f3f;
public:
int minimumMoves(vector<int>& v) {
int n = v.size();
int dp[N][N];
memset(dp, INF, sizeof(dp));
for (int i = 0; i < n; i++) {
dp[i][i] = 1;
}
for (int l = 2; l <= n; l++) { // 枚舉區間長度, 長度爲 1 的已經初始化了
for (int s = 0; s + l - 1 < n; s++) { // 枚舉區間起點 s
int e = s + l - 1;
for (int k = s; k <= e; k++) { // 找中點位置
dp[s][e] = min(dp[s][e], dp[s][k] + dp[k + 1][e]);
}
if (v[s] == v[e]) {
if (l == 2) dp[s][e] = 1;
else dp[s][e] = min(dp[s][e], dp[s + 1][e - 1]);
}
}
}
return dp[0][n - 1];
}
};