AcWing第63场周赛
思路:两层循环暴力枚举。
代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int cnt = 0;
int a, b, n;
cin >> a >> b >> n;
for(int i = 0; i <= a; i ++)
{
for(int j = 0; j <= b; j ++)
if(i + j == n)
cnt ++;
}
cout << cnt << endl;
return 0;
}
思路:用栈来模拟。当前元素和栈顶元素相同就将栈顶元素压出栈,否则就入栈,统计出栈的次数数,如果为奇数就是先手胜利,否则后手胜利。
代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
stack<char> s;
string str;
cin >> str;
int cnt = 0;
for(int i = 0; i < str.size(); i ++)
{
if(s.size() && s.top() == str[i])
{
s.pop();
cnt ++;
}
else s.push(str[i]);
}
// cout << cnt << endl;
if(cnt & 1) cout << "Yes" << endl;
else cout << "No" << endl;
return 0;
}
力扣第84场周赛
第一题:6141. 合并相似的物品 - 力扣(LeetCode)
思路:用map<int, int>来存储物品和其价值。分别将两个数组中的数据加入到map中。
代码
class Solution {
public:
vector<vector<int>> mergeSimilarItems(vector<vector<int>>& items1, vector<vector<int>>& items2) {
map<int, int> mp;
for(auto i : items1)
{
int a = i[0], b = i[1];
mp[a] += b;
}
for(auto i : items2)
{
int a = i[0], b = i[1];
mp[a] += b;
}
vector<vector<int>> ans;
for(auto [x, y] : mp) ans.push_back({x, y});
return ans;
}
};
第二题:6142. 统计坏数对的数目 - 力扣(LeetCode)
思路:统计不是坏数对个总数目n,用所有的数组减去n就是坏数对的数目。
坏数对 j - i != nums[j] - nums[i]
不是坏数对 j - i == nums[j] - nums[i] 将等式变换一下 nums[j] - j == nums[i] - i;
通过上面变换的等式我们可以将数组中的元素都减去其下标,再用map来存储数组元素相同的个数。每个数组元素相同表示从中任选两个都可以变成一个不是坏数对。
总数目和不是坏数对都是同一个数目(假设数目为m)中选择两个不行同下标:m * (m - 1) / 2
代码
class Solution {
public:
long long countBadPairs(vector<int>& nums) {
for(int i = 0; i < nums.size(); i ++) nums[i] -= i;
map<int, int> mp;
for(auto i : nums) mp[i] ++;
int n = nums.size();
long long ans = (long long)(n - 1) * n / 2;
for(auto [x, y] : mp)
ans -= (long long)y * (y - 1) / 2;
return ans;
}
};
第三题:6174. 任务调度器 II - 力扣(LeetCode)
思路:用map来模拟。map<int, int> 表示任务的完成时是第几天。
代码
class Solution {
public:
long long taskSchedulerII(vector<int>& t, int space) {
long long ans = 0;
map<int, long long> mp;
for(int i = 0; i < t.size(); i ++)
{
if(!mp.count(t[i]))
{
ans ++;
mp[t[i]] = ans;
}
else
{
ans ++;
if(ans - mp[t[i]] <= space) ans = mp[t[i]] + space + 1;
mp[t[i]] = ans;
}
// cout << ans << " ";
}
return ans;
}
};
第四题:6144. 将数组排序的最少替换次数 - 力扣(LeetCode)
思路:对数组从后向前遍历,用一个数ans来表示最小值,如果当前数大于ans,就将该数分为几个数都小于等于ans,注意每次都更新一下ans。
代码
class Solution {
public:
long long minimumReplacement(vector<int>& nums) {
long long ans = 0;
int n = nums.size();
int m = nums[n - 1];
for(int i = n - 1; i >= 0; i --)
{
if(nums[i] <= m) m = nums[i];
else
{
int t = nums[i] / m;
ans += t;
int a = nums[i] % m;
if(!a) ans --;
else
{
t ++;
m = nums[i] / t;
}
}
}
return ans;
}
};
力扣第305场周赛
第一题:2367. 算术三元组的数目 - 力扣(LeetCode)
思路:因为数据不大,可以直接暴力枚举。如果数据大一点就要将第三层替换为二分查找。
代码
朴素版(时间复杂度O(n^3))
class Solution {
public:
int arithmeticTriplets(vector<int>& nums, int diff) {
int cnt = 0, n = nums.size();
for(int i = 0; i < n; i ++)
{
for(int j = i + 1; j < n; j ++)
{
if(nums[j] - nums[i] == diff)
{
for(int k = j + 1; k < n; k ++)
{
if(nums[k] - nums[j] == diff)
cnt ++;
}
}
}
}
return cnt;
}
};
二分版(时间复杂度O(n^2logn))
代码
class Solution {
public:
int arithmeticTriplets(vector<int>& nums, int diff) {
int cnt = 0, n = nums.size();
for(int i = 0; i < n; i ++)
{
for(int j = i + 1; j < n; j ++)
{
if(nums[j] - nums[i] == diff)
{
int l = j + 1, r = n - 1;
while(l < r)
{
int mid = l + r >> 1;
if(nums[mid] - nums[j] >= diff) r = mid;
else l = mid + 1;
}
if(l < n && nums[l] - nums[j] == diff) cnt ++;
}
}
}
return cnt;
}
};
第二题:6139. 受限条件下可到达节点的数目 - 力扣(LeetCode)
思路:dfs。用dfs(u)来统计以u为根节点的子树的节点总数(节点不在受限制节点数组里)。
代码
const int N = 100010, M = 200010;
class Solution {
public:
int h[N], e[M], ne[M], idx;
bool st[N];
unordered_set<int> s;
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
int dfs(int u)
{
int sum = 1;
st[u] = 1;
for(int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if(!s.count(j) && !st[j]) sum += dfs(j);
}
return sum;
}
int reachableNodes(int n, vector<vector<int>>& edges, vector<int>& r) {
memset(h, -1, sizeof h);
memset(st, 0, sizeof st);
for(auto i : edges)
{
int a = i[0], b = i[1];
add(a, b), add(b, a);
}
// for(int i = h[0]; i != -1; i = ne[i]) cout << e[i] << " ";
for(auto i : r) s.insert(i);
// for(auto i : )
int ans = 0;
ans = dfs(0);
return ans;
}
};
第三题:2369. 检查数组是否存在有效划分 - 力扣(LeetCode)
思路:动态规划。f[i] 表示从nums[0]到nums[i - 1]是否可以有效划分。
对f[i + 1]进行讨论
第一种情况:第i个数为相等元素的第二个 i >= 1 && f[i - 1] && nums[i - 1] == nums[i]
第二种情况:第i个数为相等元素的第三个 i >= 2 && f[i - 2] && nums[i] == nums[i - 1] && nums[i - 1] == nums[i - 2]
第三种情况:第i个数为递增元素的最后一个 i >= 2 && f[i - 2] && nums[i] == nums[i - 1] + 1 && nums[i - 1] == nums[i - 2] + 1
只要满足三种情况中任意一种nums[0]到nums[i]都可以有效划分,即f[i + 1] = 1。
代码
class Solution {
public:
bool validPartition(vector<int>& nums) {
int n = nums.size();
vector<int> f(n + 1, 0);
f[0] = 1;
for(int i = 1; i < n; i ++)
{
if((f[i - 1] && nums[i] == nums[i - 1]) || (i - 2 >= 0 && f[i - 2] && nums[i] == nums[i - 1] && nums[i - 1] == nums[i - 2]) || (i - 2 >= 0 && f[i - 2] && nums[i] == nums[i - 1] + 1 && nums[i - 2] + 1 == nums[i - 1]))
f[i + 1] = 1;
}
return f[n];
}
};
第四题:2370. 最长理想子序列 - 力扣(LeetCode)
思路:动态规划。f[i]表示以i + 'a'结尾的理想字符串的最大长度。
f[i] = max(f[i], f[t] + 1) t表示在字母表中与i的绝对值位次差小于等于k。
代码
const int N = 100010;
class Solution {
public:
int f[26];
int longestIdealString(string s, int k) {
for(int i = 0; i < s.size(); i ++)
{
int u = s[i] - 'a';
f[u] = f[u] + 1;
for(int j = -k; j <= k; j ++)
{
if(!j) continue;
int t = u + j;
if(t < 0 || t >= 26) continue;
f[u] = max(f[u], f[t] + 1);
}
}
int ans = 0, m = 0;
for(int i = 0; i < 26; i ++) ans = max(ans, f[i]);
return ans;
}
};