mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-08 00:43:04 +08:00
Update
This commit is contained in:
@ -1,48 +0,0 @@
|
||||
|
||||
# 133. 小红买药
|
||||
|
||||
[题目链接](https://kamacoder.com/problempage.php?pid=1210)
|
||||
|
||||
本题是一道直观的模拟题,但也并不简单,很多情况容易漏了,笔试现场可能要多错几次 才能把情况都想到。
|
||||
|
||||
主要是三个情况:
|
||||
|
||||
* 小红没症状,药有副作用,统计加一,同时要给小红标记上症状
|
||||
* 小红有症状,药治不了,同时也没副症状 ,这时也要统计加一
|
||||
* 小红有症状,药可以治,给小红取消症状标记
|
||||
|
||||
|
||||
```CPP
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
int main() {
|
||||
int n, m, q, u;
|
||||
cin >> n;
|
||||
string s;
|
||||
cin >> s;
|
||||
cin >> m;
|
||||
vector<string> a(m + 1); // 因为后面u是从1开始的
|
||||
vector<string> b(m + 1);
|
||||
for (int i = 1; i <= m; i++) {
|
||||
cin >> a[i] >> b[i];
|
||||
}
|
||||
cin >> q;
|
||||
while (q--) {
|
||||
cin >> u;
|
||||
int num = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
// s 没症状,但b给了副作用,统计num的同时,要给s标记上症状
|
||||
if (s[i] == '0' && b[u][i] == '1') {
|
||||
num ++;
|
||||
s[i] = '1';
|
||||
}
|
||||
// s 有症状,但 a治不了,b也没副症状
|
||||
else if (s[i] == '1' && a[u][i] == '0' && a[u][i] == '0') num++;
|
||||
// s 有症状,a 可以治
|
||||
else if (s[i] == '1' && a[u][i] == '1') s[i] = '0';
|
||||
}
|
||||
cout << num << endl;
|
||||
}
|
||||
}
|
||||
```
|
@ -1,154 +0,0 @@
|
||||
|
||||
# 小红的第16版方案
|
||||
|
||||
[题目链接](https://kamacoder.com/problempage.php?pid=1240)
|
||||
|
||||
暴力解法: (数据量已经出最大了,C++能过,java、python、go都过不了)
|
||||
|
||||
```CPP
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
int main() {
|
||||
int n, m;
|
||||
int l, r;
|
||||
cin >> n >> m;
|
||||
vector<int> a(n + 1);
|
||||
vector<int> angry(n + 1);
|
||||
for (int i = 1; i <= n; i++) cin >> a[i];
|
||||
for (int i = 1; i <= m; i++) {
|
||||
cin >> l >> r;
|
||||
for (int j = l; j <= r; j++) {
|
||||
angry[j]++;
|
||||
if (angry[j] > a[j]) {
|
||||
cout << i - 1 << endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
cout << m << endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
使用 差分数组,代码如下:
|
||||
|
||||
|
||||
```CPP
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, m;
|
||||
cin >> n >> m;
|
||||
|
||||
vector<int> a(n + 1);
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
cin >> a[i];
|
||||
}
|
||||
|
||||
vector<int> diff(n + 1, 0); // 差分数组,多一个元素用于处理边界情况
|
||||
|
||||
int l, r;
|
||||
for (int i = 1; i <= m; ++i) {
|
||||
cin >> l >> r;
|
||||
diff[l]++;
|
||||
if (r + 1 <= n) diff[r + 1]--;
|
||||
}
|
||||
|
||||
int current_anger = 0; // 当前的愤怒值
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
current_anger += diff[i]; // 计算差分数组的前缀和,得到最终的愤怒值
|
||||
if (current_anger > a[i]) {
|
||||
cout << i - 1 << endl; // 如果当前的愤怒值超过阈值,输出最后一个没有问题的方案编号
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
cout << m << endl; // 如果所有修改完成后都没有超过阈值,返回最后一个方案的编号
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
过不了,因为差分数组只能知道是哪个人超过了阈值,不能知道是第几次修改超过的
|
||||
|
||||
最后 优化思路:
|
||||
|
||||
* 差分数组(Difference Array):依然使用差分数组来处理区间更新。
|
||||
* 二分查找:通过二分查找来确定最早发生愤怒值超出阈值的操作,而不是逐次模拟每一次修改。
|
||||
|
||||
步骤:
|
||||
|
||||
* 创建一个差分数组 diff 用于处理区间增加操作。
|
||||
* 在 [1, m] 的范围内进行二分查找,确定导致某个人愤怒值超过阈值的最早的修改次数。
|
||||
* 对每个二分查找的中间值 mid,我们累积应用前 mid 次操作,然后检查是否有任何人的愤怒值超过了阈值。
|
||||
* 如果 mid 之前没有超标,则继续向右查找;否则向左缩小范围。
|
||||
* 在二分查找完成后,输出找到的第一个导致愤怒值超标的操作次数。
|
||||
|
||||
```CPP
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool isValid(const vector<int>& a, const vector<int>& diff, int n, int m) {
|
||||
vector<int> anger(n + 1, 0);
|
||||
int current_anger = 0;
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
current_anger += diff[i];
|
||||
if (current_anger > a[i]) {
|
||||
return false; // 超出愤怒阈值
|
||||
}
|
||||
}
|
||||
return true; // 没有任何人超出愤怒阈值
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n, m;
|
||||
cin >> n >> m;
|
||||
|
||||
vector<int> a(n + 1); // 愤怒阈值数组
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
cin >> a[i];
|
||||
}
|
||||
|
||||
vector<pair<int, int>> operations(m + 1); // 保存每次操作的区间
|
||||
for (int i = 1; i <= m; ++i) {
|
||||
int l, r;
|
||||
cin >> l >> r;
|
||||
operations[i] = {l, r};
|
||||
}
|
||||
|
||||
int left = 1, right = m, result = m;
|
||||
|
||||
while (left <= right) {
|
||||
int mid = left + (right - left) / 2;
|
||||
|
||||
// 构建差分数组,只考虑前 mid 次操作
|
||||
vector<int> diff(n + 2, 0);
|
||||
for (int i = 1; i <= mid; ++i) {
|
||||
int l = operations[i].first;
|
||||
int r = operations[i].second;
|
||||
diff[l]++;
|
||||
if (r + 1 <= n) {
|
||||
diff[r + 1]--;
|
||||
}
|
||||
}
|
||||
|
||||
if (isValid(a, diff, n, mid)) {
|
||||
left = mid + 1; // 如果在mid次操作后没有超标,继续向右搜索
|
||||
} else {
|
||||
result = mid - 1; // 如果在mid次操作后超标,向左搜索
|
||||
right = mid - 1;
|
||||
}
|
||||
}
|
||||
|
||||
cout << result << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
* 时间复杂度:O(n + m * log m),其中 n 是成员数量,m 是操作次数。二分查找的时间复杂度为 O(log m),每次二分查找中通过差分数组检查愤怒值的复杂度为 O(n)。
|
||||
* 空间复杂度:O(n + m),主要用于存储差分数组和操作数组。
|
Reference in New Issue
Block a user