mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-08 00:43:04 +08:00
移动非代码随想录体系题目到卡码网仓库
This commit is contained in:
@ -1,27 +0,0 @@
|
|||||||
|
|
||||||
# 111. 构造二阶行列式
|
|
||||||
|
|
||||||
暴力模拟就好,每个数不超过 20, 暴力枚举其实也没多大。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
using namespace std;
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
for (int x = 1; x <= 20; x++) {
|
|
||||||
for (int y = 1; y <= 20; y++) {
|
|
||||||
for (int i = 1; i <= 20; i++) {
|
|
||||||
for (int j = 1; j <= 20; j++) {
|
|
||||||
if ((x * j - y * i) == n) {
|
|
||||||
cout << x << " " << y << endl;
|
|
||||||
cout << i << " " << j << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cout << -1 << endl;
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,26 +0,0 @@
|
|||||||
|
|
||||||
# 112. 挑战boss
|
|
||||||
|
|
||||||
本题题意有点绕,注意看一下 题目描述中的【提示信息】,但是在笔试中,是不给这样的提示信息的。
|
|
||||||
|
|
||||||
简单模拟:
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include<iostream>
|
|
||||||
using namespace std;
|
|
||||||
int main() {
|
|
||||||
int n, a, b, k = 0;
|
|
||||||
cin >> n >> a >> b;
|
|
||||||
string s;
|
|
||||||
cin >> s;
|
|
||||||
int result = 0;
|
|
||||||
for (int i = 0; i < s.size(); i++) {
|
|
||||||
int cur = a + k * b;
|
|
||||||
result += cur;
|
|
||||||
++k;
|
|
||||||
if (s[i] == 'x') k = 0;
|
|
||||||
}
|
|
||||||
cout << result << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,59 +0,0 @@
|
|||||||
|
|
||||||
# 113.国际象棋
|
|
||||||
|
|
||||||
广搜,但本题如果广搜枚举马和象的话会超时。
|
|
||||||
|
|
||||||
广搜要只枚举马的走位,同时判断是否在对角巷直接走象
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
using namespace std;
|
|
||||||
const int N = 100005, mod = 1000000007;
|
|
||||||
using ll = long long;
|
|
||||||
int n, ans;
|
|
||||||
int dir[][2] = {{1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, -1}, {-2, 1}};
|
|
||||||
int main() {
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
cin >> n;
|
|
||||||
while (n--) {
|
|
||||||
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
|
|
||||||
if (x1 == x2 && y1 == y2) {
|
|
||||||
cout << 0 << endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// 判断象走一步到达
|
|
||||||
int d = abs(x1 - x2) - abs(y1 - y2);
|
|
||||||
if (!d) {cout << 1 << endl; continue;}
|
|
||||||
// 判断马走一步到达
|
|
||||||
bool one = 0;
|
|
||||||
for (int i = 0; i < 8; ++i) {
|
|
||||||
int dx = x1 + dir[i][0], dy = y1 + dir[i][1];
|
|
||||||
if (dx == x2 && dy == y2) {
|
|
||||||
cout << 1 << endl;
|
|
||||||
one = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (one) continue;
|
|
||||||
// 接下来为两步的逻辑, 象走两步或者马走一步,象走一步
|
|
||||||
// 象直接两步可以到达,这个计算是不是同颜色的格子,象可以在两步到达所有同颜色的格子
|
|
||||||
int d2 = abs(x1 - x2) + abs(y1 - y2);
|
|
||||||
if (d2 % 2 == 0) {
|
|
||||||
cout << 2 << endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// 接下来判断马 + 象的组合
|
|
||||||
bool two = 0;
|
|
||||||
for (int i = 0; i < 8; ++i) {
|
|
||||||
int dx = x1 + dir[i][0], dy = y1 + dir[i][1];
|
|
||||||
int d = abs(dx - x2) - abs(dy - y2);
|
|
||||||
if (!d) {cout << 2 << endl; two = true; break;}
|
|
||||||
}
|
|
||||||
if (two) continue;
|
|
||||||
// 剩下的格子全都是三步到达的
|
|
||||||
cout << 3 << endl;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,29 +0,0 @@
|
|||||||
|
|
||||||
# 114. 小欧的平均数
|
|
||||||
|
|
||||||
这道题非常的脑筋急转弯, 读题都要理解半天。
|
|
||||||
|
|
||||||
初步读题,感觉好像是求 如何最小加减,得到三个数的平均数。
|
|
||||||
|
|
||||||
但题意不是这样的。
|
|
||||||
|
|
||||||
小欧的说的三个数平衡,只是三个数里 任何两个数 相加都能被2整除, 那么 也就是说,这三个数 要么都是 奇数,要么都是偶数,才能达到小欧所说的平衡。
|
|
||||||
|
|
||||||
所以题目要求的,就是,三个数,最小加减1 几次 可以让三个数都变成奇数,或者都变成偶数。
|
|
||||||
|
|
||||||
所以最终的结果 不是1 就是0,没有其他的。
|
|
||||||
|
|
||||||
录友可能想,题目出的这么绕干啥? 没办法,企业的笔试题就是这样的。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include<iostream>
|
|
||||||
#include<algorithm>
|
|
||||||
using namespace std;
|
|
||||||
int main() {
|
|
||||||
int x, y, z;
|
|
||||||
cin >> x >> y >> z;
|
|
||||||
int count = (x % 2 == 0) + (y % 2 == 0) + (z % 2 == 0);
|
|
||||||
cout << min(3 - count, count);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
|||||||
|
|
||||||
# 115. 组装手机
|
|
||||||
|
|
||||||
这道题是比较难得哈希表题目。 把代码随想录哈希表章节理解透彻,做本题没问题。
|
|
||||||
|
|
||||||
思路是
|
|
||||||
|
|
||||||
1. 用哈希表记录 外壳售价 和 手机零件售价 出现的次数
|
|
||||||
2. 记录总和出现的次数
|
|
||||||
3. 遍历总和,减去 外壳售价,看 手机零件售价出现了几次
|
|
||||||
4. 最后累加,取最大值
|
|
||||||
|
|
||||||
有一个需要注意的点: 数字可以重复,在计算个数的时候,如果计算重复的数字
|
|
||||||
|
|
||||||
例如 如果输入是
|
|
||||||
|
|
||||||
```
|
|
||||||
4
|
|
||||||
1 1 1 1
|
|
||||||
1 1 1 1
|
|
||||||
```
|
|
||||||
那么输出应该是 4, 外壳售价 和 手机零件售价 是可以重复的。
|
|
||||||
|
|
||||||
代码如下:
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <unordered_map>
|
|
||||||
using namespace std;
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
vector<int> aVec(n, 0);
|
|
||||||
vector<int> bVec(n, 0);
|
|
||||||
unordered_map<int, int > aUmap;
|
|
||||||
unordered_map<int, int > bUmap;
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
cin >> aVec[i];
|
|
||||||
aUmap[aVec[i]]++;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
cin >> bVec[i];
|
|
||||||
bUmap[bVec[i]]++;
|
|
||||||
}
|
|
||||||
unordered_set<int > uset;
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
for (int j = 0; j < n; j++){
|
|
||||||
uset.insert(aVec[i] + bVec[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int result = 0;
|
|
||||||
for (int sum : uset) {
|
|
||||||
//cout << p.first << endl;
|
|
||||||
int count = 0;
|
|
||||||
for (pair<int, int> p : aUmap) {
|
|
||||||
//cout << p.first - aVec[i] << endl;
|
|
||||||
if (sum - p.first > 0 && bUmap[sum - p.first] != 0) {
|
|
||||||
count += min(bUmap[sum - p.first], p.second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = max(result, count);
|
|
||||||
}
|
|
||||||
cout << result << endl;
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,91 +0,0 @@
|
|||||||
|
|
||||||
<p align="center"><strong><a href="./qita/join.md">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们受益!</strong></p>
|
|
||||||
|
|
||||||
# 大数减法
|
|
||||||
|
|
||||||
本题测试数据超过int 和 longlong了,所以考察的使用 string 来模拟 两个大数的 加减操作。
|
|
||||||
|
|
||||||
当然如果使用python或者Java 使用库函数都可以水过。
|
|
||||||
|
|
||||||
使用字符串来模拟过程,需要处理以下几个问题:
|
|
||||||
|
|
||||||
* 负号处理:要考虑正负数的处理,如果大数相减的结果是负数,需要在结果前加上负号。
|
|
||||||
* 大数比较:在进行减法之前,需要确定哪个数大,以便知道结果是否需要添加负号。
|
|
||||||
* 位数借位:处理大数相减时的借位问题,这类似于手动减法。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <algorithm>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
// 比较两个字符串表示的数字,返回1表示a > b,0表示a == b,-1表示a < b
|
|
||||||
int compareStrings(const string& a, const string& b) {
|
|
||||||
if (a.length() > b.length()) return 1;
|
|
||||||
if (a.length() < b.length()) return -1;
|
|
||||||
return a.compare(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 去除字符串左侧的前导零
|
|
||||||
string removeLeadingZeros(const string& num) {
|
|
||||||
size_t start = 0;
|
|
||||||
while (start < num.size() && num[start] == '0') {
|
|
||||||
start++;
|
|
||||||
}
|
|
||||||
return start == num.size() ? "0" : num.substr(start);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 大数相减,假设a >= b
|
|
||||||
string subtractStrings(const string& a, const string& b) {
|
|
||||||
string result;
|
|
||||||
int len1 = a.length(), len2 = b.length();
|
|
||||||
int carry = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < len1; i++) {
|
|
||||||
int digitA = a[len1 - 1 - i] - '0';
|
|
||||||
int digitB = i < len2 ? b[len2 - 1 - i] - '0' : 0;
|
|
||||||
|
|
||||||
int digit = digitA - digitB - carry;
|
|
||||||
if (digit < 0) {
|
|
||||||
digit += 10;
|
|
||||||
carry = 1;
|
|
||||||
} else {
|
|
||||||
carry = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.push_back(digit + '0');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 去除结果中的前导零
|
|
||||||
reverse(result.begin(), result.end());
|
|
||||||
return removeLeadingZeros(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
string subtractLargeNumbers(const string& num1, const string& num2) {
|
|
||||||
string a = num1, b = num2;
|
|
||||||
|
|
||||||
// 比较两个数的大小
|
|
||||||
int cmp = compareStrings(a, b);
|
|
||||||
|
|
||||||
if (cmp == 0) {
|
|
||||||
return "0"; // 如果两个数相等,结果为0
|
|
||||||
} else if (cmp < 0) {
|
|
||||||
// 如果a < b,交换它们并在结果前加上负号
|
|
||||||
swap(a, b);
|
|
||||||
return "-" + subtractStrings(a, b);
|
|
||||||
} else {
|
|
||||||
return subtractStrings(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
string num1, num2;
|
|
||||||
cin >> num1 >> num2;
|
|
||||||
|
|
||||||
string result = subtractLargeNumbers(num1, num2);
|
|
||||||
cout << result << endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,132 +0,0 @@
|
|||||||
|
|
||||||
# 121. 小红的区间翻转
|
|
||||||
|
|
||||||
比较暴力的方式,就是直接模拟, 枚举所有 区间,然后检查其翻转的情况。
|
|
||||||
|
|
||||||
在检查翻转的时候,需要一些代码优化,否则容易超时。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
bool canTransform(const vector<int>& a, const vector<int>& b, int left, int right) {
|
|
||||||
// 提前检查翻转区间的值是否可以匹配
|
|
||||||
for (int i = left, j = right; i <= right; i++, j--) {
|
|
||||||
if (a[i] != b[j]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 检查翻转区间外的值是否匹配
|
|
||||||
for (int i = 0; i < left; i++) {
|
|
||||||
if (a[i] != b[i]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = right + 1; i < a.size(); i++) {
|
|
||||||
if (a[i] != b[i]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
|
|
||||||
vector<int> a(n);
|
|
||||||
vector<int> b(n);
|
|
||||||
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
cin >> a[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
cin >> b[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
// 遍历所有可能的区间
|
|
||||||
for (int left = 0; left < n; left++) {
|
|
||||||
for (int right = left; right < n; right++) {
|
|
||||||
// 检查翻转区间 [left, right] 后,a 是否可以变成 b
|
|
||||||
if (canTransform(a, b, left, right)) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cout << count << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
也可以事先计算好,最长公共前缀,和最长公共后缀。
|
|
||||||
|
|
||||||
在公共前缀和公共后缀之间的部分进行翻转操作,这样我们可以减少很多不必要的翻转尝试。
|
|
||||||
|
|
||||||
通过在公共前缀和后缀之间的部分,找到可以通过翻转使得 a 和 b 相等的区间。
|
|
||||||
|
|
||||||
以下 为评论区 卡码网用户:码鬼的C++代码
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
vector<int> a(n), b(n);
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
cin >> a[i];
|
|
||||||
}
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
cin >> b[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<int> prefix(n, 0), suffix(n, 0);
|
|
||||||
|
|
||||||
// 计算前缀相等的位置
|
|
||||||
int p = 0;
|
|
||||||
while (p < n && a[p] == b[p]) {
|
|
||||||
prefix[p] = 1;
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算后缀相等的位置
|
|
||||||
int s = n - 1;
|
|
||||||
while (s >= 0 && a[s] == b[s]) {
|
|
||||||
suffix[s] = 1;
|
|
||||||
s--;
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
// 遍历所有可能的区间
|
|
||||||
for (int i = 0; i < n - 1; i++) {
|
|
||||||
for (int j = i + 1; j < n; j++) {
|
|
||||||
// 判断前缀和后缀是否相等
|
|
||||||
if ((i == 0 || prefix[i - 1] == 1) && (j == n - 1 || suffix[j + 1] == 1)) {
|
|
||||||
// 判断翻转后的子数组是否和目标数组相同
|
|
||||||
bool is_palindrome = true;
|
|
||||||
for (int k = 0; k <= (j - i) / 2; k++) {
|
|
||||||
if (a[i + k] != b[j - k]) {
|
|
||||||
is_palindrome = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (is_palindrome) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << count << endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,127 +0,0 @@
|
|||||||
|
|
||||||
# 滑动窗口最大值
|
|
||||||
|
|
||||||
本题是 [代码随想录:滑动窗口最大值](https://www.programmercarl.com/0239.%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E6%9C%80%E5%A4%A7%E5%80%BC.html) 的升级版。
|
|
||||||
|
|
||||||
在[代码随想录:滑动窗口最大值](https://www.programmercarl.com/0239.%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E6%9C%80%E5%A4%A7%E5%80%BC.html) 中详细讲解了如何求解 滑动窗口的最大值。
|
|
||||||
|
|
||||||
那么求滑动窗口的最小值原理也是一样的, 大家稍加思考,把优先级队列里的 大于 改成小于 就行了。
|
|
||||||
|
|
||||||
求最大值的优先级队列(从大到小)
|
|
||||||
```
|
|
||||||
while (!que.empty() && value > que.back()) {
|
|
||||||
```
|
|
||||||
|
|
||||||
求最小值的优先级队列(从小到大)
|
|
||||||
```
|
|
||||||
while (!que.empty() && value > que.back()) {
|
|
||||||
```
|
|
||||||
|
|
||||||
这样在滑动窗口里 最大值最小值都求出来了,遍历一遍找出 差值最大的就好。
|
|
||||||
|
|
||||||
至于输入,需要一波字符串处理,比较考察基本功。
|
|
||||||
|
|
||||||
CPP代码如下:
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <deque>
|
|
||||||
using namespace std;
|
|
||||||
class MyBigQueue { //单调队列(从大到小)
|
|
||||||
public:
|
|
||||||
deque<int> que; // 使用deque来实现单调队列
|
|
||||||
// 每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。
|
|
||||||
// 同时pop之前判断队列当前是否为空。
|
|
||||||
void pop(int value) {
|
|
||||||
if (!que.empty() && value == que.front()) {
|
|
||||||
que.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
|
|
||||||
// 这样就保持了队列里的数值是单调从大到小的了。
|
|
||||||
void push(int value) {
|
|
||||||
while (!que.empty() && value > que.back()) {
|
|
||||||
que.pop_back();
|
|
||||||
}
|
|
||||||
que.push_back(value);
|
|
||||||
|
|
||||||
}
|
|
||||||
// 查询当前队列里的最大值 直接返回队列前端也就是front就可以了。
|
|
||||||
int front() {
|
|
||||||
return que.front();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class MySmallQueue { //单调队列(从小到大)
|
|
||||||
public:
|
|
||||||
deque<int> que;
|
|
||||||
|
|
||||||
void pop(int value) {
|
|
||||||
if (!que.empty() && value == que.front()) {
|
|
||||||
que.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 和上面队列的区别是这里换成了小于,
|
|
||||||
void push(int value) {
|
|
||||||
while (!que.empty() && value < que.back()) {
|
|
||||||
que.pop_back();
|
|
||||||
}
|
|
||||||
que.push_back(value);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int front() {
|
|
||||||
return que.front();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
string input;
|
|
||||||
|
|
||||||
getline(cin, input);
|
|
||||||
|
|
||||||
vector<int> nums;
|
|
||||||
int k;
|
|
||||||
|
|
||||||
// 找到并截取nums的部分
|
|
||||||
int numsStart = input.find('[');
|
|
||||||
int numsEnd = input.find(']');
|
|
||||||
string numsStr = input.substr(numsStart + 1, numsEnd - numsStart - 1);
|
|
||||||
// cout << numsStr << endl;
|
|
||||||
|
|
||||||
// 用字符串流处理nums字符串,提取数字
|
|
||||||
stringstream ss(numsStr);
|
|
||||||
string temp;
|
|
||||||
while (getline(ss, temp, ',')) {
|
|
||||||
nums.push_back(stoi(temp));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 找到并提取k的值
|
|
||||||
int kStart = input.find("k = ") + 4;
|
|
||||||
k = stoi(input.substr(kStart));
|
|
||||||
|
|
||||||
MyBigQueue queB; // 获取区间最大值
|
|
||||||
MySmallQueue queS; // 获取区间最小值
|
|
||||||
// vector<int> result;
|
|
||||||
for (int i = 0; i < k; i++) { // 先将前k的元素放进队列
|
|
||||||
queB.push(nums[i]);
|
|
||||||
queS.push(nums[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
int result = queB.front() - queS.front();
|
|
||||||
for (int i = k; i < nums.size(); i++) {
|
|
||||||
queB.pop(nums[i - k]); // 滑动窗口移除最前面元素
|
|
||||||
queB.push(nums[i]); // 滑动窗口前加入最后面的元素
|
|
||||||
|
|
||||||
queS.pop(nums[i - k]);
|
|
||||||
queS.push(nums[i]);
|
|
||||||
|
|
||||||
result = max (result, queB.front() - queS.front());
|
|
||||||
}
|
|
||||||
cout << result << endl;
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,52 +0,0 @@
|
|||||||
|
|
||||||
121. 小红的数组构造
|
|
||||||
|
|
||||||
本题大家不要想着真去模拟数组的情况,那样就想复杂了。
|
|
||||||
|
|
||||||
数组只能是:1k、2k、3k ... (n-1)k、nk,这样 总和就是最小的。
|
|
||||||
|
|
||||||
注意最后的和可能超过int,所以用 long long。
|
|
||||||
|
|
||||||
代码如下:
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
using namespace std;
|
|
||||||
int main () {
|
|
||||||
long long result = 0;
|
|
||||||
int n, k;
|
|
||||||
cin >> n >> k;
|
|
||||||
for (int i = 1; i <= n; i++) {
|
|
||||||
result += i * k;
|
|
||||||
}
|
|
||||||
cout << result << endl;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
优化思路:
|
|
||||||
|
|
||||||
|
|
||||||
由于要计算1到n的整数之和,可以利用等差数列求和公式来优化计算。
|
|
||||||
|
|
||||||
和公式:1 + 2 + 3 + ... + n = n * (n + 1) / 2
|
|
||||||
|
|
||||||
因此,总和 result = k * (n * (n + 1) / 2)
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
long long result = 0;
|
|
||||||
int n, k;
|
|
||||||
cin >> n >> k;
|
|
||||||
|
|
||||||
// 使用等差数列求和公式进行计算
|
|
||||||
result = k * (n * (n + 1LL) / 2);
|
|
||||||
|
|
||||||
cout << result << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,38 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
# 122.精华帖子
|
|
||||||
|
|
||||||
|
|
||||||
开辟一个数组,默认都是0,把精华帖标记为1.
|
|
||||||
|
|
||||||
使用前缀和,快速计算出,k 范围内 有多少个精华帖。
|
|
||||||
|
|
||||||
前缀和要特别注意区间问题,即 vec[i+k] - vec[i] 求得区间和是 (i, i + k] 这个区间,注意这是一个左开右闭的区间。
|
|
||||||
|
|
||||||
所以前缀和 很容易漏掉 vec[0] 这个数值的计算
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
int main() {
|
|
||||||
int n, m, k, l, r;
|
|
||||||
cin >> n >> m >> k;
|
|
||||||
vector<int> vec(n);
|
|
||||||
while (m--) {
|
|
||||||
cin >> l >> r;
|
|
||||||
for (int i = l; i < r; i++) vec[i] = 1;
|
|
||||||
}
|
|
||||||
int result = 0;
|
|
||||||
for (int i = 0; i < k; i++) result += vec[i]; // 提前预处理result,包含vec[0]的区间,否则前缀和容易漏掉这个区间
|
|
||||||
|
|
||||||
for (int i = 1; i < n; i++) {
|
|
||||||
vec[i] += vec[i - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < n - k; i++) {
|
|
||||||
result = max (result, vec[i + k] - vec[i]);
|
|
||||||
}
|
|
||||||
cout << result << endl;
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,66 +0,0 @@
|
|||||||
|
|
||||||
# 123.连续子数组最大和
|
|
||||||
|
|
||||||
这道题目可以说是 [代码随想录,动态规划:最大子序和](https://www.programmercarl.com/0053.%E6%9C%80%E5%A4%A7%E5%AD%90%E5%BA%8F%E5%92%8C%EF%BC%88%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%EF%BC%89.html) 的升级版。
|
|
||||||
|
|
||||||
题目求的是 可以替换一个数字 之后 的 连续子数组最大和。
|
|
||||||
|
|
||||||
如果替换的是数组下标 i 的元素。
|
|
||||||
|
|
||||||
那么可以用 [代码随想录,动态规划:最大子序和](https://www.programmercarl.com/0053.%E6%9C%80%E5%A4%A7%E5%AD%90%E5%BA%8F%E5%92%8C%EF%BC%88%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%EF%BC%89.html) 的方法,先求出 [0 - i) 区间的 最大子序和 dp1 和 (i, n)的最大子序和dp2 。
|
|
||||||
|
|
||||||
然后在遍历一遍i, 计算 dp1 + dp2 + vec[i] 的最大值就可以。
|
|
||||||
|
|
||||||
正序遍历,求出 [0 - i) 区间的 最大子序,dp[ i - 1] 表示 是 包括下标i - 1(以vec[i - 1]为结尾)的最大连续子序列和为dp[i - 1]。
|
|
||||||
|
|
||||||
所以 在计算区间 (i, n)即 dp2 的时候,我们要倒叙。 因为我们求的是以 包括下标i + 1 为起始位置的最大连续子序列和为dp[i + 1]。
|
|
||||||
|
|
||||||
这样 dp1 + dp2 + vec[i] 才是一个完整区间。
|
|
||||||
|
|
||||||
这里就体现出对 dp数组定义的把控,本题如果对 dp数组含义理解不清,其实是不容易做出来的。
|
|
||||||
|
|
||||||
代码:
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <climits>
|
|
||||||
using namespace std;
|
|
||||||
int main() {
|
|
||||||
int t, n, x;
|
|
||||||
cin >> t;
|
|
||||||
while (t--) {
|
|
||||||
cin >> n >> x;
|
|
||||||
vector<int> vec(n);
|
|
||||||
for (int i = 0; i < n; i++) cin >> vec[i];
|
|
||||||
vector<int> dp1(n);
|
|
||||||
dp1[0] = vec[0];
|
|
||||||
int res = vec[0];
|
|
||||||
// 从前向后统计最大子序和
|
|
||||||
for (int i = 1; i < n; i++) {
|
|
||||||
dp1[i] = max(dp1[i - 1] + vec[i], vec[i]); // 状态转移公式
|
|
||||||
res = max(res, dp1[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = max(res, vec[n - 1]);
|
|
||||||
// 从后向前统计最大子序和
|
|
||||||
vector<int> dp2(n);
|
|
||||||
dp2[n - 1] = vec[n - 1];
|
|
||||||
for (int i = n - 2; i >= 0; i--) {
|
|
||||||
dp2[i] = max(dp2[i + 1] + vec[i], vec[i]);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0 ; i < n ; i++) {
|
|
||||||
int dp1res = 0;
|
|
||||||
if (i > 0) dp1res = max(dp1[i-1], 0);
|
|
||||||
int dp2res = 0;
|
|
||||||
if (i < n - 1 ) dp2res = max(dp2[i+1], 0);
|
|
||||||
|
|
||||||
res = max(res, dp1res + dp2res + x);
|
|
||||||
}
|
|
||||||
cout << res << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,29 +0,0 @@
|
|||||||
|
|
||||||
# 小美的排列询问
|
|
||||||
|
|
||||||
模拟题,注意 x 和y 不分先后
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
int main() {
|
|
||||||
int n, x, y;
|
|
||||||
cin >> n;
|
|
||||||
vector<int> vec(n, 0);
|
|
||||||
for (int i =0; i < n; i++) {
|
|
||||||
cin >> vec[i];
|
|
||||||
}
|
|
||||||
cin >> x >> y;
|
|
||||||
for (int i = 0; i < n - 1; i++) {
|
|
||||||
if (x == vec[i] && y == vec[i + 1]) || (y == vec[i] && x == vec[i + 1]) ) {
|
|
||||||
cout << "Yes" << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cout << "No" << endl;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,35 +0,0 @@
|
|||||||
|
|
||||||
# 小美走公路
|
|
||||||
|
|
||||||
在处理环形情况的时候,很多录友容易算懵了,不是多算一个数,就是少算一个数。
|
|
||||||
|
|
||||||
这里这样的题目,最好的方式是将 两个环展开,首尾相连,这样我们就可以通过 直线的思维去解题了
|
|
||||||
|
|
||||||
两个注意点:
|
|
||||||
|
|
||||||
1. x 可以比 y 大,题目没规定 x 和y 的大小顺序
|
|
||||||
2. 累计相加的数可能超过int
|
|
||||||
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
int main () {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
vector<int> vec(2* n + 1, 0);
|
|
||||||
for (int i = 1; i <= n; i++) {
|
|
||||||
cin >> vec[i];
|
|
||||||
vec[n + i] = vec[i];
|
|
||||||
}
|
|
||||||
int x, y;
|
|
||||||
cin >> x >> y;
|
|
||||||
int xx = min(x ,y); // 注意点1:x 可以比 y 大
|
|
||||||
int yy = max(x, y);
|
|
||||||
long long a = 0, b = 0; // 注意点2:相加的数可能超过int
|
|
||||||
for (int i = xx; i < yy; i++) a += vec[i];
|
|
||||||
for (int i = yy; i < xx + n; i++ ) b += vec[i];
|
|
||||||
cout << min(a, b) << endl;
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,51 +0,0 @@
|
|||||||
|
|
||||||
# 小美的蛋糕切割
|
|
||||||
|
|
||||||
二维前缀和,不了解前缀和的录友 可以自行查一下,是一个很容易理解的算法思路
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <climits>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
int main () {
|
|
||||||
int n, m;
|
|
||||||
cin >> n >> m;
|
|
||||||
int sum = 0;
|
|
||||||
vector<vector<int>> vec(n, vector<int>(m, 0)) ;
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
for (int j = 0; j < m; j++) {
|
|
||||||
cin >> vec[i][j];
|
|
||||||
sum += vec[i][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 统计横向
|
|
||||||
vector<int> horizontal(n, 0);
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
for (int j = 0 ; j < m; j++) {
|
|
||||||
horizontal[i] += vec[i][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 统计纵向
|
|
||||||
vector<int> vertical(m , 0);
|
|
||||||
for (int j = 0; j < m; j++) {
|
|
||||||
for (int i = 0 ; i < n; i++) {
|
|
||||||
vertical[j] += vec[i][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int result = INT_MAX;
|
|
||||||
int horizontalCut = 0;
|
|
||||||
for (int i = 0 ; i < n; i++) {
|
|
||||||
horizontalCut += horizontal[i];
|
|
||||||
result = min(result, abs(sum - horizontalCut - horizontalCut));
|
|
||||||
}
|
|
||||||
int verticalCut = 0;
|
|
||||||
for (int j = 0; j < m; j++) {
|
|
||||||
verticalCut += vertical[j];
|
|
||||||
result = min(result, abs(sum - verticalCut - verticalCut));
|
|
||||||
}
|
|
||||||
cout << result << endl;
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,78 +0,0 @@
|
|||||||
|
|
||||||
# 130.小美的字符串变换
|
|
||||||
|
|
||||||
本题是[岛屿数量](./0099.岛屿的数量广搜.md)的进阶版,主要思路和代码都是一样的,统计一个图里岛屿的数量,也是染色问题。
|
|
||||||
|
|
||||||
1、 先枚举各个可能出现的矩阵
|
|
||||||
2、 针对矩阵经行广搜染色(深搜,并查集一样可以)
|
|
||||||
3、 统计岛屿数量最小的数量。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <climits>
|
|
||||||
#include <vector>
|
|
||||||
#include <queue>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
// 广搜代码同 卡码网:99. 岛屿数量
|
|
||||||
int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向
|
|
||||||
void bfs(const vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y, char a) {
|
|
||||||
queue<pair<int, int>> que;
|
|
||||||
que.push({x, y});
|
|
||||||
visited[x][y] = true; // 只要加入队列,立刻标记
|
|
||||||
while(!que.empty()) {
|
|
||||||
pair<int ,int> cur = que.front(); que.pop();
|
|
||||||
int curx = cur.first;
|
|
||||||
int cury = cur.second;
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
int nextx = curx + dir[i][0];
|
|
||||||
int nexty = cury + dir[i][1];
|
|
||||||
if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue; // 越界了,直接跳过
|
|
||||||
if (!visited[nextx][nexty] && grid[nextx][nexty] == a) {
|
|
||||||
que.push({nextx, nexty});
|
|
||||||
visited[nextx][nexty] = true; // 只要加入队列立刻标记
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
string s;
|
|
||||||
cin >> n;
|
|
||||||
int result = INT_MAX;
|
|
||||||
cin >> s;
|
|
||||||
for (int k = 1; k < n; k++) {
|
|
||||||
if (n % k != 0) continue;
|
|
||||||
// 计算出 矩阵的 行 和 列
|
|
||||||
int x = n / k;
|
|
||||||
int y = k;
|
|
||||||
//cout << x << " " << y << endl;
|
|
||||||
vector<vector<char>> vec(x, vector<char>(y, 0));
|
|
||||||
// 填装矩阵
|
|
||||||
int sCount = 0;
|
|
||||||
for (int i = 0; i < x; i++) {
|
|
||||||
for (int j = 0; j < y; j++) {
|
|
||||||
vec[i][j] = s[sCount++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 开始广搜染色
|
|
||||||
vector<vector<bool>> visited(x, vector<bool>(y, false));
|
|
||||||
int count = 0;
|
|
||||||
for (int i = 0; i < x; i++) {
|
|
||||||
for (int j = 0; j < y; j++) {
|
|
||||||
|
|
||||||
if (!visited[i][j]) {
|
|
||||||
count++; // 遇到没访问过的陆地,+1
|
|
||||||
bfs(vec, visited, i, j, vec[i][j]); // 将与其链接的陆地都标记上 true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 取岛屿数量最少的
|
|
||||||
result = min (result, count);
|
|
||||||
|
|
||||||
}
|
|
||||||
cout << result << endl;
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,134 +0,0 @@
|
|||||||
# 131. 小美的树上染色
|
|
||||||
|
|
||||||
本题为树形dp 稍有难度,主要在于 递推公式上。
|
|
||||||
|
|
||||||
dp数组的定义:
|
|
||||||
|
|
||||||
dp[cur][1] :当前节点染色,那么当前节点为根节点及其左右子节点中,可以染色的最大数量
|
|
||||||
|
|
||||||
dp[cur][0] :当前节点不染色,那么当前节点为根节点及其左右子节点中,可以染色的最大数量
|
|
||||||
|
|
||||||
关于 dp转移方程
|
|
||||||
|
|
||||||
1、 情况一:
|
|
||||||
|
|
||||||
如果当前节点不染色,那就去 子节点 染色 或者 不染色的最大值。
|
|
||||||
|
|
||||||
`dp[cur][0] += max(dp[child][0], dp[child][1]);`
|
|
||||||
|
|
||||||
|
|
||||||
2、情况二:
|
|
||||||
|
|
||||||
那么当前节点染色的话,这种情况就不好想了。
|
|
||||||
|
|
||||||
首先这不是二叉树,每一个节点都有可能 会有n个子节点。
|
|
||||||
|
|
||||||
所以我们要分别讨论,每一个子节点的情况 对父节点的影响。
|
|
||||||
|
|
||||||
那么父节点 针对每种情况,就要去 最大值, 也就是 `dp[cur][1] = max(dp[cur][1], 每个自孩子的情况)`
|
|
||||||
|
|
||||||
如图,假如节点1 是我们要计算的父节点,节点2是我们这次要计算的子节点。
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
选中一个节点2 作为我们这次计算的子节点,父节点染色的话,子节点必染色。
|
|
||||||
|
|
||||||
接下来就是计算 父节点1和该子节点2染色的话, 以子节点2 为根的 染色节点的最大数量 。
|
|
||||||
|
|
||||||
是:节点2不染色 且 以节点2为根节点的最大 染色数量 + 2, + 2 是因为 节点 1 和 节点2 要颜色了,染色节点增加两个。
|
|
||||||
|
|
||||||
代码:`dp[child][0] + 2`
|
|
||||||
|
|
||||||
细心的录友会发现,那我们只计算了 红色框里面的,那么框外 最大的染色数量是多少呢?
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
先看 作为子节点的节点2 为根节点的最大染色数量是多少? 取一个最值,即 节点2染色 或者 不染色取最大值。
|
|
||||||
|
|
||||||
代码:`max(dp[child][0], dp[child][1])`
|
|
||||||
|
|
||||||
那么红框以外的 染色最大节点数量 就是 `dp[cur][0] - max(dp[child][0], dp[child][1])`
|
|
||||||
|
|
||||||
(cur是节点1,child是节点2)
|
|
||||||
|
|
||||||
红框以外的染色最大数量 + 父节点1和该子节点2染色的话 以子节点2 为根的 染色节点的最大数量 就是 节点1 染色的最大节点数量。
|
|
||||||
|
|
||||||
代码:
|
|
||||||
|
|
||||||
`dp[cur][1] = max(dp[cur][1], dp[cur][0] - max(dp[child][0], dp[child][1]) + dp[child][0] + 2);`
|
|
||||||
|
|
||||||
整体代码如下:
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <cmath>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int maxN = 10005;
|
|
||||||
vector<vector<int>> dp (maxN, vector<int>(2, 0));
|
|
||||||
vector<list<int>> grid(maxN); // 邻接表
|
|
||||||
vector<long> value(maxN); // 存储每个节点的权值
|
|
||||||
|
|
||||||
|
|
||||||
// 在树上进行动态规划的函数
|
|
||||||
void dpOnTheTree(int cur) {
|
|
||||||
|
|
||||||
for (int child : grid[cur]) {
|
|
||||||
// 后序遍历,从下向上计算
|
|
||||||
dpOnTheTree(child);
|
|
||||||
// 情况一
|
|
||||||
dp[cur][0] += max(dp[child][0], dp[child][1]);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算dp[1] - 当前节点染色
|
|
||||||
for (int child : grid[cur]) {
|
|
||||||
long mul = value[cur] * value[child]; // 当前节点和相邻节点权值的乘积
|
|
||||||
long sqrtNum = (long) sqrt(mul);
|
|
||||||
|
|
||||||
if (sqrtNum * sqrtNum == mul) { // 如果乘积是完全平方数
|
|
||||||
// 情况二
|
|
||||||
// dp[cur][0] 表示所有子节点 染色或者不染色的 最大染色数量
|
|
||||||
// max(dp[child][0], dp[child][1]) 需要染色节点的孩子节点的最大染色数量
|
|
||||||
// dp[cur][0] - max(dp[child][0], dp[child][1]) 除了要染色的节点及其子节点,其他孩子的最大染色数量
|
|
||||||
// 最后 + dp[child][0] + 2 , 就是本节点染色的最大染色节点数量
|
|
||||||
dp[cur][1] = max(dp[cur][1], dp[cur][0] - max(dp[child][0], dp[child][1]) + dp[child][0] + 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
|
|
||||||
int n;
|
|
||||||
cin >> n; // 输入节点数量
|
|
||||||
|
|
||||||
// 读取节点权值
|
|
||||||
for (int i = 1; i <= n; ++i) {
|
|
||||||
cin >> value[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建树的邻接表
|
|
||||||
for (int i = 1; i < n; ++i) {
|
|
||||||
int x, y;
|
|
||||||
cin >> x >> y;
|
|
||||||
grid[x].push_back(y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从根节点(节点1)开始进行动态规划
|
|
||||||
dpOnTheTree(1);
|
|
||||||
|
|
||||||
// 输出最大染色节点数量
|
|
||||||
cout << max(dp[1][0], dp[1][1]) << endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
|||||||
|
|
||||||
# 132. 夹吃棋
|
|
||||||
|
|
||||||
[题目链接](https://kamacoder.com/problempage.php?pid=1209)
|
|
||||||
|
|
||||||
这道题是模拟题,但很多录友可能想复杂了。
|
|
||||||
|
|
||||||
行方向,白棋吃,只有这样的布局 `o*o`,黑棋吃,只有这样的布局 `*o*`
|
|
||||||
|
|
||||||
列方向也是同理的。
|
|
||||||
|
|
||||||
想到这一点,本题的代码就容易写了, C++代码如下:
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
while (n--) {
|
|
||||||
int black = 0, white = 0;
|
|
||||||
vector<string> grid(3, "");
|
|
||||||
// 判断行
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
cin >> grid[i];
|
|
||||||
if (grid[i] == "o*o") white++;
|
|
||||||
if (grid[i] == "*o*") black++;
|
|
||||||
}
|
|
||||||
// 判断列
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
string s;
|
|
||||||
s += grid[0][i];
|
|
||||||
s += grid[1][i];
|
|
||||||
s += grid[2][i];
|
|
||||||
if (s == "o*o") white++;
|
|
||||||
if (s == "*o*") black++;
|
|
||||||
}
|
|
||||||
// 如果一个棋盘的局面没有一方被夹吃或者黑白双方都被对面夹吃,则认为是平局
|
|
||||||
if ((!white && !black) || (white && black)) cout << "draw" << endl;
|
|
||||||
// 白棋赢
|
|
||||||
else if (white && !black) cout << "yukan" << endl;
|
|
||||||
// 黑棋赢
|
|
||||||
else cout << "kou" << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,77 +0,0 @@
|
|||||||
|
|
||||||
# 134. 皇后移动的最小步数
|
|
||||||
|
|
||||||
[题目链接](https://kamacoder.com/problempage.php?pid=1211)
|
|
||||||
|
|
||||||
本题和 [代码随想录-不同路径](https://www.programmercarl.com/0062.%E4%B8%8D%E5%90%8C%E8%B7%AF%E5%BE%84.html) 有一些类似。
|
|
||||||
|
|
||||||
关键是弄清楚递推公式
|
|
||||||
|
|
||||||
一共分三个情况,
|
|
||||||
|
|
||||||
情况一,向右移动:
|
|
||||||
|
|
||||||
然后从 (i, j) 再向右走 到 (i, k)。 无论k 多大,步数只加1 :
|
|
||||||
|
|
||||||
`dp[i][k] = dp[i][j] + 1`
|
|
||||||
|
|
||||||
那么 `dp[i][k]` 也有可能 从其他方向得到,例如 从上到下, 或者斜上方到达 dp[i][k]
|
|
||||||
|
|
||||||
本题我们要求最小步数,所以取最小值:`dp[i][k] = min(dp[i][k], dp[i][j] + 1);`
|
|
||||||
|
|
||||||
情况二,向下移动:
|
|
||||||
|
|
||||||
从 (i, j) 再向下走 到 (k, j)。 无论k 多大,步数只加1 :
|
|
||||||
|
|
||||||
`dp[k][j] = dp[i][j] + 1;`
|
|
||||||
|
|
||||||
同理 `dp[i][k]` 也有可能 从其他方向得到,取最小值:`dp[k][j] = min(dp[k][j], dp[i][j] + 1);`
|
|
||||||
|
|
||||||
情况三,右下方移动:
|
|
||||||
|
|
||||||
从 (i, j) 再向右下方移动 到 (i + k, j + k)。 无论k 多大,步数只加1 :
|
|
||||||
|
|
||||||
`dp[i + k][j + k] = dp[i][j] + 1`
|
|
||||||
|
|
||||||
同理 `dp[i + k][j + k]` 也有可能 从其他方向得到,取最小值:`dp[i + k][j + k] = min(dp[i + k][j + k], dp[i][j] + 1);`
|
|
||||||
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
const int INF = 4e6; // 最多步数也就是 2000 * 2000
|
|
||||||
int main() {
|
|
||||||
int n, m;
|
|
||||||
cin >> n >> m;
|
|
||||||
vector<vector<char>> grid(n, vector<char>(m));
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
for (int j = 0; j < m; j++) {
|
|
||||||
cin >> grid[i][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vector<vector<int>> dp(n, vector<int>(m, INF));
|
|
||||||
dp[0][0] = 0;
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
for (int j = 0; j < m; j++) {
|
|
||||||
if (grid[i][j] == '*') continue;
|
|
||||||
// 向右移动k个格子
|
|
||||||
for (int k = j + 1; k < m && grid[i][k] == '.'; k++) {
|
|
||||||
dp[i][k] = min(dp[i][k], dp[i][j] + 1);
|
|
||||||
}
|
|
||||||
// 向下移动 k个格子
|
|
||||||
for (int k = i + 1; k < n && grid[k][j] == '.'; k++) {
|
|
||||||
dp[k][j] = min(dp[k][j], dp[i][j] + 1);
|
|
||||||
}
|
|
||||||
// 向右下移动k个格子
|
|
||||||
for (int k = 1; i + k < n && j + k < m && grid[i + k][j + k] == '.'; k++) {
|
|
||||||
dp[i + k][j + k] = min(dp[i + k][j + k], dp[i][j] + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dp[n - 1][m - 1] == INF) cout << -1 << endl;
|
|
||||||
else cout << dp[n - 1][m - 1] << endl;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
@ -1,147 +0,0 @@
|
|||||||
|
|
||||||
# 135. 获取连通的相邻节点列表
|
|
||||||
|
|
||||||
本题是一个 “阅读理解”题,其实题目的算法很简单,但理解题意很费劲。
|
|
||||||
|
|
||||||
题目描述中的【提示信息】 是我后加上去了,华为笔试的时候没有这个 【提示信息】。
|
|
||||||
|
|
||||||
相信没有 【提示信息】大家理解题意 平均要多用半个小时。
|
|
||||||
|
|
||||||
思路:
|
|
||||||
|
|
||||||
1. 将第一行数据加入set中
|
|
||||||
2. 后面输出数据,判断是否在 set里
|
|
||||||
3. 最后把结果排个序
|
|
||||||
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <unordered_set>
|
|
||||||
using namespace std;
|
|
||||||
int main() {
|
|
||||||
unordered_set<int> uset;
|
|
||||||
int n, a;
|
|
||||||
cin >> n;
|
|
||||||
while (n--) {
|
|
||||||
cin >> a;
|
|
||||||
uset.insert(a);
|
|
||||||
}
|
|
||||||
int m, x, vlan_id;
|
|
||||||
long long tb;
|
|
||||||
vector<long long> vecTB;
|
|
||||||
cin >> m;
|
|
||||||
while(m--) {
|
|
||||||
cin >> tb;
|
|
||||||
cin >> x;
|
|
||||||
vector<long long> vecVlan_id(x);
|
|
||||||
for (int i = 0; i < x; i++) {
|
|
||||||
cin >> vecVlan_id[i];
|
|
||||||
}
|
|
||||||
for (int i = 0; i < x; i++) {
|
|
||||||
if (uset.find(vecVlan_id[i]) != uset.end()) {
|
|
||||||
vecTB.push_back(tb);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
cout << vecTB.size() << endl;
|
|
||||||
if (vecTB.size() != 0) {
|
|
||||||
sort(vecTB.begin(), vecTB.end());
|
|
||||||
for (int i = 0; i < vecTB.size() ; i++) cout << vecTB[i] << " ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## 其他语言版本
|
|
||||||
|
|
||||||
### Java
|
|
||||||
|
|
||||||
```Java
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Scanner scanner = new Scanner(System.in);
|
|
||||||
Set<Integer> uset = new HashSet<>();
|
|
||||||
int n = scanner.nextInt();
|
|
||||||
while (n-- > 0) {
|
|
||||||
int a = scanner.nextInt();
|
|
||||||
uset.add(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
int m = scanner.nextInt();
|
|
||||||
List<Long> vecTB = new ArrayList<>();
|
|
||||||
while (m-- > 0) {
|
|
||||||
long tb = scanner.nextLong();
|
|
||||||
int x = scanner.nextInt();
|
|
||||||
List<Integer> vecVlan_id = new ArrayList<>();
|
|
||||||
for (int i = 0; i < x; i++) {
|
|
||||||
vecVlan_id.add(scanner.nextInt());
|
|
||||||
}
|
|
||||||
for (int vlanId : vecVlan_id) {
|
|
||||||
if (uset.contains(vlanId)) {
|
|
||||||
vecTB.add(tb);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println(vecTB.size());
|
|
||||||
if (!vecTB.isEmpty()) {
|
|
||||||
Collections.sort(vecTB);
|
|
||||||
for (long tb : vecTB) {
|
|
||||||
System.out.print(tb + " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
### Python
|
|
||||||
|
|
||||||
```python
|
|
||||||
def main():
|
|
||||||
import sys
|
|
||||||
input = sys.stdin.read
|
|
||||||
data = input().split()
|
|
||||||
|
|
||||||
index = 0
|
|
||||||
n = int(data[index])
|
|
||||||
index += 1
|
|
||||||
uset = set()
|
|
||||||
for _ in range(n):
|
|
||||||
a = int(data[index])
|
|
||||||
index += 1
|
|
||||||
uset.add(a)
|
|
||||||
|
|
||||||
m = int(data[index])
|
|
||||||
index += 1
|
|
||||||
vecTB = []
|
|
||||||
while m > 0:
|
|
||||||
tb = int(data[index])
|
|
||||||
index += 1
|
|
||||||
x = int(data[index])
|
|
||||||
index += 1
|
|
||||||
vecVlan_id = []
|
|
||||||
for _ in range(x):
|
|
||||||
vecVlan_id.append(int(data[index]))
|
|
||||||
index += 1
|
|
||||||
for vlan_id in vecVlan_id:
|
|
||||||
if vlan_id in uset:
|
|
||||||
vecTB.append(tb)
|
|
||||||
break
|
|
||||||
m -= 1
|
|
||||||
|
|
||||||
print(len(vecTB))
|
|
||||||
if vecTB:
|
|
||||||
vecTB.sort()
|
|
||||||
print(" ".join(map(str, vecTB)))
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
```
|
|
@ -1,148 +0,0 @@
|
|||||||
|
|
||||||
# 字符串处理器
|
|
||||||
|
|
||||||
纯模拟,但情况比较多,非常容易 空指针异常。
|
|
||||||
|
|
||||||
大家要注意,边界问题 以及 负数问题。
|
|
||||||
|
|
||||||
整体代码如下:
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include<bits/stdc++.h>
|
|
||||||
using namespace std;
|
|
||||||
int main() {
|
|
||||||
int index = 0;
|
|
||||||
long long optNum;
|
|
||||||
string s;
|
|
||||||
string cmd;
|
|
||||||
while(cin >> cmd){
|
|
||||||
//cout << s << endl;
|
|
||||||
if(cmd == "insert") {
|
|
||||||
string buff;
|
|
||||||
cin >> buff;
|
|
||||||
s.insert(index, buff);
|
|
||||||
index += buff.size();
|
|
||||||
}
|
|
||||||
else if(cmd == "move") {
|
|
||||||
cin >> optNum;
|
|
||||||
if(optNum > 0 && index + optNum <= s.size()) index += optNum;
|
|
||||||
if(optNum < 0 && index >= -optNum) index += optNum;
|
|
||||||
}
|
|
||||||
else if(cmd == "delete") {
|
|
||||||
cin >> optNum;
|
|
||||||
if(index >= optNum && optNum > 0){
|
|
||||||
s.erase(index - optNum, optNum);
|
|
||||||
index -= optNum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(cmd == "copy") {
|
|
||||||
if(index > 0) {
|
|
||||||
string tmp = s.substr(0, index);
|
|
||||||
s.insert(index, tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(cmd == "end") {
|
|
||||||
for(int i = 0; i < index; i++) {
|
|
||||||
cout << s[i];
|
|
||||||
}
|
|
||||||
cout << '|';
|
|
||||||
for(int i = index; i < s.size(); i++) cout << s[i];
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## 其他语言版本
|
|
||||||
|
|
||||||
### Java
|
|
||||||
|
|
||||||
```Java
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Scanner scanner = new Scanner(System.in);
|
|
||||||
StringBuilder s = new StringBuilder();
|
|
||||||
int index = 0;
|
|
||||||
int optNum;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
String cmd = scanner.next();
|
|
||||||
if (cmd.equals("insert")) {
|
|
||||||
String buff = scanner.next();
|
|
||||||
s.insert(index, buff);
|
|
||||||
index += buff.length();
|
|
||||||
} else if (cmd.equals("move")) {
|
|
||||||
optNum = scanner.nextInt();
|
|
||||||
if (optNum > 0 && index + optNum <= s.length()) index += optNum;
|
|
||||||
if (optNum < 0 && index >= -optNum) index += optNum;
|
|
||||||
} else if (cmd.equals("delete")) {
|
|
||||||
optNum = scanner.nextInt();
|
|
||||||
if (index >= optNum && optNum > 0) {
|
|
||||||
s.delete(index - optNum, index);
|
|
||||||
index -= optNum;
|
|
||||||
}
|
|
||||||
} else if (cmd.equals("copy")) {
|
|
||||||
if (index > 0) {
|
|
||||||
String tmp = s.substring(0, index);
|
|
||||||
s.insert(index, tmp);
|
|
||||||
}
|
|
||||||
} else if (cmd.equals("end")) {
|
|
||||||
System.out.print(s.substring(0, index) + '|' + s.substring(index));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scanner.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Python
|
|
||||||
|
|
||||||
```python
|
|
||||||
def main():
|
|
||||||
import sys
|
|
||||||
input = sys.stdin.read
|
|
||||||
data = input().split()
|
|
||||||
s = ""
|
|
||||||
index = 0
|
|
||||||
i = 0
|
|
||||||
|
|
||||||
while i < len(data):
|
|
||||||
cmd = data[i]
|
|
||||||
i += 1
|
|
||||||
if cmd == "insert":
|
|
||||||
buff = data[i]
|
|
||||||
i += 1
|
|
||||||
s = s[:index] + buff + s[index:]
|
|
||||||
index += len(buff)
|
|
||||||
elif cmd == "move":
|
|
||||||
optNum = int(data[i])
|
|
||||||
i += 1
|
|
||||||
if optNum > 0 and index + optNum <= len(s):
|
|
||||||
index += optNum
|
|
||||||
elif optNum < 0 and index >= -optNum:
|
|
||||||
index += optNum
|
|
||||||
elif cmd == "delete":
|
|
||||||
optNum = int(data[i])
|
|
||||||
i += 1
|
|
||||||
if index >= optNum and optNum > 0:
|
|
||||||
s = s[:index - optNum] + s[index:]
|
|
||||||
index -= optNum
|
|
||||||
elif cmd == "copy":
|
|
||||||
if index > 0:
|
|
||||||
tmp = s[:index]
|
|
||||||
s = s[:index] + tmp + s[index:]
|
|
||||||
elif cmd == "end":
|
|
||||||
print(s[:index] + '|' + s[index:])
|
|
||||||
break
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
@ -1,192 +0,0 @@
|
|||||||
|
|
||||||
# 137. 消息传输
|
|
||||||
|
|
||||||
这道题目,普通广搜就可以解决。
|
|
||||||
|
|
||||||
这里说一下几点注意事项:
|
|
||||||
|
|
||||||
1、 题目描述中,注意 n 是列数,m是行数
|
|
||||||
|
|
||||||
这是造成很多录友周赛的时候提交 返回 【运行错误】的罪魁祸首,如果 输入用例是 正方形,那没问题,如果后台输入用例是矩形, n 和 m 搞反了,就会数组越界。
|
|
||||||
|
|
||||||
矩阵是 m * n ,但输入的顺序却是 先输入n 再输入 m。
|
|
||||||
|
|
||||||
这会让很多人把矩阵的 n 和 m 搞反。
|
|
||||||
|
|
||||||
其实规范出题,就应该是n 行,m列,然后 先输入n,在输入m。
|
|
||||||
|
|
||||||
只能说 大厂出题的人,也不是专业出题的,所以会在 非算法方面一不小心留下很多 “bug”,消耗大家的精力。
|
|
||||||
|
|
||||||
2、再写广搜的时候,可能担心会无限循环
|
|
||||||
|
|
||||||
即 A 走到 B,B又走到A,A又走到B ,这种情况,一般来说 广搜都是用一个 visit数组来标记的。
|
|
||||||
|
|
||||||
但本题不用,因为 不会重复走的,题图里的信号都是正数,根据距离判断大小 可以保证不走回头路。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <queue>
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
const int inf = 1e6;
|
|
||||||
int main () {
|
|
||||||
int n, m, startx, starty;
|
|
||||||
cin >> n >> m;
|
|
||||||
cin >> startx >> starty;
|
|
||||||
vector<vector<int>> grid(m, vector<int>(n));
|
|
||||||
vector<vector<int>> dis(m, vector<int>(n, inf));
|
|
||||||
for (int i = 0; i < m; i++) {
|
|
||||||
for (int j = 0; j < n; j++) {
|
|
||||||
cin >> grid[i][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
queue<pair<int, int>> que;
|
|
||||||
int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1};
|
|
||||||
que.push(pair<int, int>(startx, starty));
|
|
||||||
dis[startx][starty] = 0;
|
|
||||||
while(!que.empty()) {
|
|
||||||
pair<int, int> cur = que.front(); que.pop();
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
int newx = cur.first + dir[i][1];
|
|
||||||
int newy = cur.second + dir[i][0];
|
|
||||||
if (newx < 0 || newx >= m || newy < 0 || newy >= n || grid[cur.first][cur.second] == 0) continue;
|
|
||||||
|
|
||||||
if (dis[newx][newy] > dis[cur.first][cur.second] + grid[cur.first][cur.second]) {
|
|
||||||
dis[newx][newy] = dis[cur.first][cur.second] + grid[cur.first][cur.second];
|
|
||||||
que.push(pair<int, int>(newx, newy));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int result = 0;
|
|
||||||
for (int i = 0; i < m; i++) {
|
|
||||||
for (int j = 0; j < n; j++) {
|
|
||||||
if (dis[i][j] == inf) {
|
|
||||||
cout << -1 << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
result = max(result, dis[i][j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cout << result << endl;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 其他语言版本
|
|
||||||
|
|
||||||
### Java
|
|
||||||
|
|
||||||
```Java
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
static final int INF = 1000000;
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Scanner scanner = new Scanner(System.in);
|
|
||||||
int n = scanner.nextInt();
|
|
||||||
int m = scanner.nextInt();
|
|
||||||
int startX = scanner.nextInt();
|
|
||||||
int startY = scanner.nextInt();
|
|
||||||
|
|
||||||
int[][] grid = new int[m][n];
|
|
||||||
int[][] dis = new int[m][n];
|
|
||||||
|
|
||||||
for (int i = 0; i < m; i++) {
|
|
||||||
Arrays.fill(dis[i], INF);
|
|
||||||
for (int j = 0; j < n; j++) {
|
|
||||||
grid[i][j] = scanner.nextInt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Queue<int[]> queue = new LinkedList<>();
|
|
||||||
int[][] directions = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};
|
|
||||||
|
|
||||||
queue.add(new int[]{startX, startY});
|
|
||||||
dis[startX][startY] = 0;
|
|
||||||
|
|
||||||
while (!queue.isEmpty()) {
|
|
||||||
int[] current = queue.poll();
|
|
||||||
for (int[] dir : directions) {
|
|
||||||
int newX = current[0] + dir[0];
|
|
||||||
int newY = current[1] + dir[1];
|
|
||||||
if (newX >= 0 && newX < m && newY >= 0 && newY < n && grid[current[0]][current[1]] != 0) {
|
|
||||||
if (dis[newX][newY] > dis[current[0]][current[1]] + grid[current[0]][current[1]]) {
|
|
||||||
dis[newX][newY] = dis[current[0]][current[1]] + grid[current[0]][current[1]];
|
|
||||||
queue.add(new int[]{newX, newY});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
for (int i = 0; i < m; i++) {
|
|
||||||
for (int j = 0; j < n; j++) {
|
|
||||||
if (dis[i][j] == INF) {
|
|
||||||
System.out.println(-1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
result = Math.max(result, dis[i][j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println(result);
|
|
||||||
scanner.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Python
|
|
||||||
|
|
||||||
```Python
|
|
||||||
from collections import deque
|
|
||||||
|
|
||||||
inf = 1000000
|
|
||||||
|
|
||||||
def main():
|
|
||||||
import sys
|
|
||||||
input = sys.stdin.read
|
|
||||||
data = input().split()
|
|
||||||
index = 0
|
|
||||||
|
|
||||||
n = int(data[index])
|
|
||||||
m = int(data[index+1])
|
|
||||||
startx = int(data[index+2])
|
|
||||||
starty = int(data[index+3])
|
|
||||||
index += 4
|
|
||||||
|
|
||||||
grid = []
|
|
||||||
dis = [[inf] * n for _ in range(m)]
|
|
||||||
|
|
||||||
for i in range(m):
|
|
||||||
grid.append([int(data[index+j]) for j in range(n)])
|
|
||||||
index += n
|
|
||||||
|
|
||||||
directions = [(0, 1), (1, 0), (-1, 0), (0, -1)]
|
|
||||||
queue = deque()
|
|
||||||
queue.append((startx, starty))
|
|
||||||
dis[startx][starty] = 0
|
|
||||||
|
|
||||||
while queue:
|
|
||||||
curx, cury = queue.popleft()
|
|
||||||
for dx, dy in directions:
|
|
||||||
newx, newy = curx + dx, cury + dy
|
|
||||||
if 0 <= newx < m and 0 <= newy < n and grid[curx][cury] != 0:
|
|
||||||
if dis[newx][newy] > dis[curx][cury] + grid[curx][cury]:
|
|
||||||
dis[newx][newy] = dis[curx][cury] + grid[curx][cury]
|
|
||||||
queue.append((newx, newy))
|
|
||||||
|
|
||||||
result = 0
|
|
||||||
for i in range(m):
|
|
||||||
for j in range(n):
|
|
||||||
if dis[i][j] == inf:
|
|
||||||
print(-1)
|
|
||||||
return
|
|
||||||
result = max(result, dis[i][j])
|
|
||||||
|
|
||||||
print(result)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
@ -1,101 +0,0 @@
|
|||||||
|
|
||||||
# 可爱串
|
|
||||||
|
|
||||||
整体思路,就含有 子序列的字符串数量 减去 含有子串的字符串数量。
|
|
||||||
|
|
||||||
因为子序列数量已经是包含子串数量的。 剩下的就是 只有子序列 且没有子串的 字符串数量。
|
|
||||||
|
|
||||||
|
|
||||||
需要注意我们求的不是 长度为 i 的字符串里有多少个 red 子序列。
|
|
||||||
|
|
||||||
**而是 可以有多少个 长度为i 的字符串 含有子序列 red**
|
|
||||||
|
|
||||||
同理,可以有多少个长度为i的字符串含有 red 子串
|
|
||||||
|
|
||||||
认清这一点很重要!
|
|
||||||
|
|
||||||
### 求子串
|
|
||||||
|
|
||||||
dp2[i][3] 长度为i 且 含有子串 red 的字符串数量 有多少
|
|
||||||
|
|
||||||
dp2[i][2] 长度为i 且 含有子串 re 的字符串数量有多少
|
|
||||||
|
|
||||||
dp2[i][1] 长度为 i 且 含有子串 r 的字符串数量有多少
|
|
||||||
|
|
||||||
dp2[1][0] 长度为 i 且 含有 只有 de, ee , e, d的字符串的字符串数量有多少。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
// 求子串
|
|
||||||
dp2[0][0] = 1;
|
|
||||||
for(int i = 1;i <= n; i++) {
|
|
||||||
dp2[i][0] = (dp2[i - 1][2] + dp2[i - 1][1] + dp2[i - 1][0] * 2) % mod; // 含有 re 的可以把 r改成d, 含有r 的可以改成
|
|
||||||
dp2[i][1] = (dp2[i - 1][2] + dp2[i - 1][1] + dp2[i - 1][0]) % mod;
|
|
||||||
dp2[i][2] = (dp2[i - 1][1]);
|
|
||||||
dp2[i][3] = (dp2[i - 1][3] * 3 + dp2[i - 1][2]) % mod;
|
|
||||||
}
|
|
||||||
``
|
|
||||||
|
|
||||||
### 求子序列
|
|
||||||
|
|
||||||
dp1[i][3] 长度为i 且 含有子序列 red 的字符串数量 有多少
|
|
||||||
|
|
||||||
dp2[i][2] 长度为i 且 含有子序列 re 的字符串数量有多少
|
|
||||||
|
|
||||||
dp2[i][1] 长度为 i 且 含有子序列 r 的字符串数量有多少
|
|
||||||
|
|
||||||
dp2[1][0] 长度为 i 且 含有 只含有 e 和 d 的字符串的字符串数量有多少。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
|
|
||||||
// 求子序列
|
|
||||||
dp1[0][0]=1;
|
|
||||||
for(int i=1;i<=n;i++)
|
|
||||||
{
|
|
||||||
dp1[i][0] = (dp1[i - 1][0] * 2) % mod;
|
|
||||||
dp1[i][1] = (dp1[i - 1][0] + dp1[i - 1][1] * 2) % mod;
|
|
||||||
dp1[i][2] = (dp1[i - 1][1] + dp1[i - 1][2] * 2) % mod;
|
|
||||||
dp1[i][3] = (dp1[i - 1][2] + dp1[i - 1][3] * 3) % mod;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
|
|
||||||
#include <bits/stdc++.h>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
using ll=long long;
|
|
||||||
const int mod=1e9+7;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
|
|
||||||
cin>>n;
|
|
||||||
vector<vector<ll>> dp1(n + 1,vector<ll> (4,0));
|
|
||||||
vector<vector<ll>> dp2(n + 1,vector<ll> (4,0));
|
|
||||||
// 求子串
|
|
||||||
dp2[0][0] = 1;
|
|
||||||
for(int i = 1;i <= n; i++) {
|
|
||||||
dp2[i][0] = (dp2[i - 1][2] + dp2[i - 1][1] + dp2[i - 1][0] * 2) % mod;
|
|
||||||
dp2[i][1] = (dp2[i - 1][2] + dp2[i - 1][1] + dp2[i - 1][0]) % mod;
|
|
||||||
dp2[i][2] = (dp2[i - 1][1]);
|
|
||||||
dp2[i][3] = (dp2[i - 1][3] * 3 + dp2[i - 1][2]) % mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 求子序列
|
|
||||||
dp1[0][0]=1;
|
|
||||||
for(int i=1;i<=n;i++)
|
|
||||||
{
|
|
||||||
dp1[i][0] = (dp1[i - 1][0] * 2) % mod;
|
|
||||||
dp1[i][1] = (dp1[i - 1][0] + dp1[i - 1][1] * 2) % mod;
|
|
||||||
dp1[i][2] = (dp1[i - 1][1] + dp1[i - 1][2] * 2) % mod;
|
|
||||||
dp1[i][3] = (dp1[i - 1][2] + dp1[i - 1][3] * 3) % mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout<<(dp1[n][3] - dp2[n][3])%mod;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,29 +0,0 @@
|
|||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
int countOnes(long long num) {
|
|
||||||
int zeroCount = 0;
|
|
||||||
while (num > 0) {
|
|
||||||
if (num % 10 != 0) { // 检查最低位是否为0
|
|
||||||
zeroCount++;
|
|
||||||
}
|
|
||||||
num /= 10; // 移除最低位
|
|
||||||
}
|
|
||||||
return zeroCount;
|
|
||||||
}
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
vector<int> vec(n);
|
|
||||||
for (int i = 0; i < n; i++) cin >> vec[i];
|
|
||||||
int result = 0;
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
for (int j = i + 1; j < n; j++) {
|
|
||||||
if (countOnes(vec[i] * vec[j]) == 1) result++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cout << result << endl;
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,104 +0,0 @@
|
|||||||
|
|
||||||
本题和 [96.不同的二叉搜索树](https://www.programmercarl.com/0096.%E4%B8%8D%E5%90%8C%E7%9A%84%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91.html) 比较像
|
|
||||||
|
|
||||||
* 取模这里很容易出错
|
|
||||||
* 过程中所用到的数值都有可能超过int,所以要改用longlong
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
long long mod = 1e9 + 7;
|
|
||||||
long long dp(int t, vector<long long>& memory) {
|
|
||||||
if (t % 2 == 0) return 0;
|
|
||||||
if (t == 1) return 1;
|
|
||||||
if (memory[t] != -1) return memory[t];
|
|
||||||
|
|
||||||
long long result = 0;
|
|
||||||
// 枚举左右子树节点的数量
|
|
||||||
for (int i = 1; i < t; i += 2) {
|
|
||||||
long long leftNum = dp(i, memory); // 左子树节点数量为i
|
|
||||||
long long rightNum = dp(t - i - 1, memory); // 右子树节点数量为t - i - 1
|
|
||||||
result += (leftNum * rightNum) % mod; // 注意这里是乘的关系
|
|
||||||
result %= mod;
|
|
||||||
}
|
|
||||||
memory[t] = result;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
vector<long long> memory(n + 1, -1);
|
|
||||||
cout << dp(n, memory) << endl;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
const int MOD = 1000000007;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int num;
|
|
||||||
cin >> num;
|
|
||||||
|
|
||||||
if (num % 2 == 0) {
|
|
||||||
cout << 0 << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<long long> dp(num + 1, 0);
|
|
||||||
dp[1] = 1;
|
|
||||||
|
|
||||||
for (int i = 3; i <= num; i += 2) {
|
|
||||||
for (int j = 1; j <= i - 2; j += 2) {
|
|
||||||
dp[i] = (dp[i] + dp[j] * dp[i - 1 - j]) % MOD;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << dp[num] << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
第二题的代码
|
|
||||||
|
|
||||||
#include <bits/stdc++.h>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
long fastexp(long base,long n,long mod){
|
|
||||||
long answer = 1;
|
|
||||||
while(n > 0){
|
|
||||||
if(n % 2 == 1){
|
|
||||||
answer = (answer * base) % mod;
|
|
||||||
}
|
|
||||||
base = (base * base) % mod;
|
|
||||||
n /= 2;
|
|
||||||
}
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
int kawaiiStrings(int n) {
|
|
||||||
// write code here
|
|
||||||
std::vector<long> f(n + 1), g(n + 1), h(n + 1);
|
|
||||||
long mod = 1000000007;
|
|
||||||
for (long i = 2; i <= n; i++) g[i] = (g[i - 1] * 2 + (i - 1) * fastexp(2,i-2,mod)) % mod;
|
|
||||||
for (long i = 3; i <= n; i++) f[i] = ((f[i - 1] * 3) % mod + g[i - 1]) % mod;
|
|
||||||
for (long i = 3; i <= n; i++) h[i] = (fastexp(3, i - 3, mod) + h[i - 1] * 3 - h[i - 3]) % mod;
|
|
||||||
return (f[n]-h[n]+mod)%mod;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(){
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
cout << kawaiiStrings(n) << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,108 +0,0 @@
|
|||||||
|
|
||||||
# 142. 两个字符串的最小 ASCII 删除总和
|
|
||||||
|
|
||||||
本题和[代码随想录:两个字符串的删除操作](https://www.programmercarl.com/0583.%E4%B8%A4%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E5%88%A0%E9%99%A4%E6%93%8D%E4%BD%9C.html) 思路基本是一样的。
|
|
||||||
|
|
||||||
属于编辑距离问题,如果想彻底了解,建议看看「代码随想录」的编辑距离总结篇。
|
|
||||||
|
|
||||||
本题dp数组含义:
|
|
||||||
|
|
||||||
dp[i][j] 表示 以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最小ASCII 删除总和。
|
|
||||||
|
|
||||||
如果 s1[i - 1] 与 s2[j - 1] 相同,则不用删:`dp[i][j] = dp[i - 1][j - 1]`
|
|
||||||
|
|
||||||
如果 s1[i - 1] 与 s2[j - 1] 不相同,删word1 的 最小删除和: `dp[i - 1][j] + s1[i - 1]` ,删word2的最小删除和: `dp[i][j - 1] + s2[j - 1]`
|
|
||||||
|
|
||||||
取最小值: `dp[i][j] = min(dp[i - 1][j] + s1[i - 1], dp[i][j - 1] + s2[j - 1])`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
int main() {
|
|
||||||
string s1, s2;
|
|
||||||
cin >> s1 >> s2;
|
|
||||||
vector<vector<int>> dp(s1.size() + 1, vector<int>(s2.size() + 1, 0));
|
|
||||||
|
|
||||||
// s1 如果变成空串的最小删除ASCLL值综合
|
|
||||||
for (int i = 1; i <= s1.size(); i++) dp[i][0] = dp[i - 1][0] + s1[i - 1];
|
|
||||||
// s2 如果变成空串的最小删除ASCLL值综合
|
|
||||||
for (int j = 1; j <= s2.size(); j++) dp[0][j] = dp[0][j - 1] + s2[j - 1];
|
|
||||||
|
|
||||||
for (int i = 1; i <= s1.size(); i++) {
|
|
||||||
for (int j = 1; j <= s2.size(); j++) {
|
|
||||||
if (s1[i - 1] == s2[j - 1]) dp[i][j] = dp[i - 1][j - 1];
|
|
||||||
else dp[i][j] = min(dp[i - 1][j] + s1[i - 1], dp[i][j - 1] + s2[j - 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cout << dp[s1.size()][s2.size()] << endl;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Java
|
|
||||||
|
|
||||||
```Java
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Scanner scanner = new Scanner(System.in);
|
|
||||||
String s1 = scanner.nextLine();
|
|
||||||
String s2 = scanner.nextLine();
|
|
||||||
int[][] dp = new int[s1.length() + 1][s2.length() + 1];
|
|
||||||
|
|
||||||
// s1 如果变成空串的最小删除ASCII值综合
|
|
||||||
for (int i = 1; i <= s1.length(); i++) {
|
|
||||||
dp[i][0] = dp[i - 1][0] + s1.charAt(i - 1);
|
|
||||||
}
|
|
||||||
// s2 如果变成空串的最小删除ASCII值综合
|
|
||||||
for (int j = 1; j <= s2.length(); j++) {
|
|
||||||
dp[0][j] = dp[0][j - 1] + s2.charAt(j - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 1; i <= s1.length(); i++) {
|
|
||||||
for (int j = 1; j <= s2.length(); j++) {
|
|
||||||
if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
|
|
||||||
dp[i][j] = dp[i - 1][j - 1];
|
|
||||||
} else {
|
|
||||||
dp[i][j] = Math.min(dp[i - 1][j] + s1.charAt(i - 1), dp[i][j - 1] + s2.charAt(j - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
System.out.println(dp[s1.length()][s2.length()]);
|
|
||||||
scanner.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
### python
|
|
||||||
|
|
||||||
```python
|
|
||||||
def min_delete_sum(s1: str, s2: str) -> int:
|
|
||||||
dp = [[0] * (len(s2) + 1) for _ in range(len(s1) + 1)]
|
|
||||||
|
|
||||||
# s1 如果变成空串的最小删除ASCII值综合
|
|
||||||
for i in range(1, len(s1) + 1):
|
|
||||||
dp[i][0] = dp[i - 1][0] + ord(s1[i - 1])
|
|
||||||
# s2 如果变成空串的最小删除ASCII值综合
|
|
||||||
for j in range(1, len(s2) + 1):
|
|
||||||
dp[0][j] = dp[0][j - 1] + ord(s2[j - 1])
|
|
||||||
|
|
||||||
for i in range(1, len(s1) + 1):
|
|
||||||
for j in range(1, len(s2) + 1):
|
|
||||||
if s1[i - 1] == s2[j - 1]:
|
|
||||||
dp[i][j] = dp[i - 1][j - 1]
|
|
||||||
else:
|
|
||||||
dp[i][j] = min(dp[i - 1][j] + ord(s1[i - 1]), dp[i][j - 1] + ord(s2[j - 1]))
|
|
||||||
|
|
||||||
return dp[len(s1)][len(s2)]
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
s1 = input().strip()
|
|
||||||
s2 = input().strip()
|
|
||||||
print(min_delete_sum(s1, s2))
|
|
||||||
```
|
|
@ -1,237 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
# 143. 最长同值路径
|
|
||||||
|
|
||||||
|
|
||||||
本题两个考点:
|
|
||||||
|
|
||||||
1. 层序遍历构造二叉树
|
|
||||||
2. 树形dp,找出最长路径
|
|
||||||
|
|
||||||
对于写代码不多,或者动手能力比较差的录友,第一个 构造二叉树 基本就被卡主了。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <queue>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
// 定义二叉树节点结构
|
|
||||||
struct TreeNode {
|
|
||||||
int val;
|
|
||||||
TreeNode* left;
|
|
||||||
TreeNode* right;
|
|
||||||
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 根据层序遍历数组构建二叉树
|
|
||||||
TreeNode* constructBinaryTree(const vector<string>& levelOrder) {
|
|
||||||
if (levelOrder.empty()) return NULL;
|
|
||||||
|
|
||||||
TreeNode* root = new TreeNode(stoi(levelOrder[0]));
|
|
||||||
queue<TreeNode*> q;
|
|
||||||
q.push(root);
|
|
||||||
int i = 1;
|
|
||||||
|
|
||||||
while (!q.empty() && i < levelOrder.size()) {
|
|
||||||
TreeNode* current = q.front();
|
|
||||||
q.pop();
|
|
||||||
|
|
||||||
if (i < levelOrder.size() && levelOrder[i] != "null") {
|
|
||||||
current->left = new TreeNode(stoi(levelOrder[i]));
|
|
||||||
q.push(current->left);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (i < levelOrder.size() && levelOrder[i] != "null") {
|
|
||||||
current->right = new TreeNode(stoi(levelOrder[i]));
|
|
||||||
q.push(current->right);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
// 树形DP
|
|
||||||
int dfs(TreeNode* node) {
|
|
||||||
if (node == NULL) return 0;
|
|
||||||
int leftPath = dfs(node->left);
|
|
||||||
int rightPath = dfs(node->right);
|
|
||||||
|
|
||||||
int leftNum = 0, rightNum = 0;
|
|
||||||
if (node->left != NULL && node->left->val == node->val) {
|
|
||||||
leftNum = leftPath + 1;
|
|
||||||
}
|
|
||||||
if (node->right != NULL && node->right->val == node->val) {
|
|
||||||
rightNum = rightPath + 1;
|
|
||||||
}
|
|
||||||
result = max(result, leftNum + rightNum);
|
|
||||||
return max(leftNum, rightNum);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
vector<string> levelOrder(n);
|
|
||||||
for (int i = 0; i < n ; i++) cin >> levelOrder[i];
|
|
||||||
|
|
||||||
TreeNode* root = constructBinaryTree(levelOrder);
|
|
||||||
dfs(root);
|
|
||||||
cout << result << endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Java
|
|
||||||
|
|
||||||
```Java
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
class TreeNode {
|
|
||||||
int val;
|
|
||||||
TreeNode left, right;
|
|
||||||
TreeNode(int x) {
|
|
||||||
val = x;
|
|
||||||
left = null;
|
|
||||||
right = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
public static int result = 0;
|
|
||||||
|
|
||||||
public static TreeNode constructBinaryTree(List<String> levelOrder) {
|
|
||||||
if (levelOrder.isEmpty()) return null;
|
|
||||||
|
|
||||||
TreeNode root = new TreeNode(Integer.parseInt(levelOrder.get(0)));
|
|
||||||
Queue<TreeNode> queue = new LinkedList<>();
|
|
||||||
queue.add(root);
|
|
||||||
int i = 1;
|
|
||||||
|
|
||||||
while (!queue.isEmpty() && i < levelOrder.size()) {
|
|
||||||
TreeNode current = queue.poll();
|
|
||||||
|
|
||||||
if (i < levelOrder.size() && !levelOrder.get(i).equals("null")) {
|
|
||||||
current.left = new TreeNode(Integer.parseInt(levelOrder.get(i)));
|
|
||||||
queue.add(current.left);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (i < levelOrder.size() && !levelOrder.get(i).equals("null")) {
|
|
||||||
current.right = new TreeNode(Integer.parseInt(levelOrder.get(i)));
|
|
||||||
queue.add(current.right);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int dfs(TreeNode node) {
|
|
||||||
if (node == null) return 0;
|
|
||||||
int leftPath = dfs(node.left);
|
|
||||||
int rightPath = dfs(node.right);
|
|
||||||
|
|
||||||
int leftNum = 0, rightNum = 0;
|
|
||||||
if (node.left != null && node.left.val == node.val) {
|
|
||||||
leftNum = leftPath + 1;
|
|
||||||
}
|
|
||||||
if (node.right != null && node.right.val == node.val) {
|
|
||||||
rightNum = rightPath + 1;
|
|
||||||
}
|
|
||||||
result = Math.max(result, leftNum + rightNum);
|
|
||||||
return Math.max(leftNum, rightNum);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Scanner sc = new Scanner(System.in);
|
|
||||||
int n = sc.nextInt();
|
|
||||||
sc.nextLine(); // consume the newline character
|
|
||||||
List<String> levelOrder = new ArrayList<>();
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
levelOrder.add(sc.next());
|
|
||||||
}
|
|
||||||
TreeNode root = constructBinaryTree(levelOrder);
|
|
||||||
dfs(root);
|
|
||||||
System.out.println(result);
|
|
||||||
sc.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
### python
|
|
||||||
|
|
||||||
```python
|
|
||||||
from typing import List, Optional
|
|
||||||
from collections import deque
|
|
||||||
import sys
|
|
||||||
|
|
||||||
class TreeNode:
|
|
||||||
def __init__(self, val: int = 0, left: 'TreeNode' = None, right: 'TreeNode' = None):
|
|
||||||
self.val = val
|
|
||||||
self.left = left
|
|
||||||
self.right = right
|
|
||||||
|
|
||||||
def construct_binary_tree(level_order: List[str]) -> Optional[TreeNode]:
|
|
||||||
if not level_order:
|
|
||||||
return None
|
|
||||||
|
|
||||||
root = TreeNode(int(level_order[0]))
|
|
||||||
queue = deque([root])
|
|
||||||
i = 1
|
|
||||||
|
|
||||||
while queue and i < len(level_order):
|
|
||||||
current = queue.popleft()
|
|
||||||
|
|
||||||
if i < len(level_order) and level_order[i] != "null":
|
|
||||||
current.left = TreeNode(int(level_order[i]))
|
|
||||||
queue.append(current.left)
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
if i < len(level_order) and level_order[i] != "null":
|
|
||||||
current.right = TreeNode(int(level_order[i]))
|
|
||||||
queue.append(current.right)
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
return root
|
|
||||||
|
|
||||||
result = 0
|
|
||||||
|
|
||||||
def dfs(node: Optional[TreeNode]) -> int:
|
|
||||||
global result
|
|
||||||
if node is None:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
left_path = dfs(node.left)
|
|
||||||
right_path = dfs(node.right)
|
|
||||||
|
|
||||||
left_num = right_num = 0
|
|
||||||
if node.left is not None and node.left.val == node.val:
|
|
||||||
left_num = left_path + 1
|
|
||||||
if node.right is not None and node.right.val == node.val:
|
|
||||||
right_num = right_path + 1
|
|
||||||
|
|
||||||
result = max(result, left_num + right_num)
|
|
||||||
return max(left_num, right_num)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
input = sys.stdin.read
|
|
||||||
data = input().strip().split()
|
|
||||||
|
|
||||||
n = int(data[0])
|
|
||||||
level_order = data[1:]
|
|
||||||
|
|
||||||
root = construct_binary_tree(level_order)
|
|
||||||
dfs(root)
|
|
||||||
print(result)
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
@ -1,66 +0,0 @@
|
|||||||
|
|
||||||
# 0144.字典序最小的01字符串
|
|
||||||
|
|
||||||
贪心思路:移动尽可能 移动前面的1 ,这样可以是 字典序最小
|
|
||||||
|
|
||||||
从前到后遍历,遇到 0 ,就用前面的 1 来交换
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
using namespace std;
|
|
||||||
int main() {
|
|
||||||
int n,k;
|
|
||||||
cin >> n >> k;
|
|
||||||
string s;
|
|
||||||
cin >> s;
|
|
||||||
for(int i = 0; i < n && k > 0; i++) {
|
|
||||||
if(s[i] == '0') {
|
|
||||||
// 开始用前面的 1 来交换
|
|
||||||
int j = i;
|
|
||||||
while(j > 0 && s[j - 1] == '1' && k > 0) {
|
|
||||||
swap(s[j], s[j - 1]);
|
|
||||||
--j;
|
|
||||||
--k;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cout << s << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Java:
|
|
||||||
|
|
||||||
```Java
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Scanner scanner = new Scanner(System.in);
|
|
||||||
int n = scanner.nextInt();
|
|
||||||
int k = scanner.nextInt();
|
|
||||||
scanner.nextLine(); // 消耗掉换行符
|
|
||||||
String s = scanner.nextLine();
|
|
||||||
char[] ch = s.toCharArray();
|
|
||||||
|
|
||||||
for (int i = 0; i < n && k > 0; i++) {
|
|
||||||
if (ch[i] == '0') {
|
|
||||||
// 开始用前面的 1 来交换
|
|
||||||
int j = i;
|
|
||||||
while (j > 0 && ch[j - 1] == '1' && k > 0) {
|
|
||||||
char tmp = ch[j];
|
|
||||||
ch[j] = ch[j - 1];
|
|
||||||
ch[j - 1] = tmp;
|
|
||||||
j--;
|
|
||||||
k--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println(new String(ch));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,98 +0,0 @@
|
|||||||
|
|
||||||
# 145. 数组子序列的排列
|
|
||||||
|
|
||||||
每个元素出现的次数相乘就可以了。
|
|
||||||
|
|
||||||
注意 “长度为 m 的数组,1 到 m 每个元素都出现过,且恰好出现 1 次。” ,题目中有n个元素,所以我们要统计的就是 1 到 n 元素出现的个数。
|
|
||||||
|
|
||||||
因为如果有一个元素x 大于n了, 那不可能出现 长度为x的数组 且 1 到 x 每个元素都出现过。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include "bits/stdc++.h"
|
|
||||||
using namespace std;
|
|
||||||
int main(){
|
|
||||||
int n;
|
|
||||||
int x;
|
|
||||||
cin >> n;
|
|
||||||
unordered_map<int, int> umap;
|
|
||||||
for(int i = 0; i < n; ++i){
|
|
||||||
cin >> x;
|
|
||||||
if(umap.find(x) != umap.end()) umap[x]++;
|
|
||||||
else umap[x] = 1;
|
|
||||||
}
|
|
||||||
long long res = 0;
|
|
||||||
long long num = 1;
|
|
||||||
for (int i = 1; i <= n; i++) {
|
|
||||||
if (umap.find(i) == umap.end()) break; // 如果i都没出现,后面得数也不能 1 到 m 每个元素都出现过
|
|
||||||
num = (num * umap[i]) % 1000000007;
|
|
||||||
res += num;
|
|
||||||
res %= 1000000007;
|
|
||||||
}
|
|
||||||
cout << res << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
```Java
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Scanner sc = new Scanner(System.in);
|
|
||||||
int n = sc.nextInt();
|
|
||||||
Map<Integer, Integer> map = new HashMap<>();
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
int x = sc.nextInt();
|
|
||||||
map.put(x, map.getOrDefault(x, 0) + 1);
|
|
||||||
}
|
|
||||||
long res = 0;
|
|
||||||
long num = 1;
|
|
||||||
for (int i = 1; i <= n; i++) {
|
|
||||||
if (!map.containsKey(i)) break; // 如果i都没出现,后面得数也不能1到m每个元素都出现过
|
|
||||||
num = (num * map.get(i)) % 1000000007;
|
|
||||||
res += num;
|
|
||||||
res %= 1000000007;
|
|
||||||
}
|
|
||||||
System.out.println(res);
|
|
||||||
sc.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
```python
|
|
||||||
def main():
|
|
||||||
import sys
|
|
||||||
input = sys.stdin.read
|
|
||||||
data = input().split()
|
|
||||||
|
|
||||||
n = int(data[0])
|
|
||||||
umap = {}
|
|
||||||
|
|
||||||
for i in range(1, n + 1):
|
|
||||||
x = int(data[i])
|
|
||||||
if x in umap:
|
|
||||||
umap[x] += 1
|
|
||||||
else:
|
|
||||||
umap[x] = 1
|
|
||||||
|
|
||||||
res = 0
|
|
||||||
num = 1
|
|
||||||
MOD = 1000000007
|
|
||||||
|
|
||||||
for i in range(1, n + 1):
|
|
||||||
if i not in umap:
|
|
||||||
break # 如果i都没出现,后面得数也不能1到m每个元素都出现过
|
|
||||||
num = (num * umap[i]) % MOD
|
|
||||||
res = (res + num) % MOD
|
|
||||||
|
|
||||||
print(res)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|
||||||
```
|
|
@ -1,65 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 146. 传送树
|
|
||||||
|
|
||||||
本题题意是比较绕的,我后面给补上了 【提示信息】对 题目输出样例讲解一下,相对会容易理解的多。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <algorithm>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
vector<vector<int>> edge; // 邻接表来存图
|
|
||||||
vector<int> nxt;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 递归函数,用于找到每个节点的下一个传送门节点,并记录在nxt数组中。
|
|
||||||
* 遍历当前节点的所有子节点,递归调用findNext以确保子节点的nxt值已经计算出来。
|
|
||||||
* 更新当前节点的nxt值为其子节点中编号最小的节点。
|
|
||||||
* 如果当前节点是叶子节点(即没有子节点),则将其nxt值设置为自身。
|
|
||||||
*/
|
|
||||||
void findNext(int node) {
|
|
||||||
for (int v : edge[node]) {
|
|
||||||
findNext(v);
|
|
||||||
if (nxt[node] == -1 || nxt[node] > min(v, nxt[v])) {
|
|
||||||
nxt[node] = min(v, nxt[v]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 叶子节点
|
|
||||||
if (nxt[node] == -1) {
|
|
||||||
nxt[node] = node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算从节点u出发经过若干次传送门到达叶子节点所需的步数。
|
|
||||||
// 通过不断访问nxt节点,直到到达叶子节点,记录访问的节点数。
|
|
||||||
int get(int u) {
|
|
||||||
int cnt = 1;
|
|
||||||
while (nxt[u] != u) {
|
|
||||||
cnt++;
|
|
||||||
u = nxt[u];
|
|
||||||
}
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
cin >> n;
|
|
||||||
edge.resize(n + 1);
|
|
||||||
nxt.resize(n + 1, -1);
|
|
||||||
for (int i = 1; i <= n; ++i) {
|
|
||||||
int a, b;
|
|
||||||
cin >> a >> b;
|
|
||||||
edge[a].push_back(b);
|
|
||||||
}
|
|
||||||
findNext(1);
|
|
||||||
for (int i = 1; i <= n; ++i) {
|
|
||||||
cout << get(i) << ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,78 +0,0 @@
|
|||||||
|
|
||||||
# 三珠互斥
|
|
||||||
|
|
||||||
1. 如果k * 3 大于 n 了,那说明一定没结果,如果没想明白,大家举个例子试试看
|
|
||||||
2. 分别求出三个红珠子之间的距离
|
|
||||||
3. 对这三段距离从小到大排序 y1, y2, y3
|
|
||||||
4. 如果第一段距离y1 小于k,说明需要交换 k - y 次, 同理 第二段距离y2 小于k,说明需要交换 k - y2 次
|
|
||||||
5. y1 y2 都调整好了,不用计算y3,因为 y3是距离最大
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include<bits/stdc++.h>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main(){
|
|
||||||
int t;
|
|
||||||
cin >> t;
|
|
||||||
int n, k, a1, a2, a3;
|
|
||||||
vector<int> dis(3);
|
|
||||||
|
|
||||||
while (t--) {
|
|
||||||
cin >> n >> k >> a1 >> a2 >> a3;
|
|
||||||
if(k * 3 > n){
|
|
||||||
cout << -1 << endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
dis[0] = min(abs(a1 - a2), n - abs(a1 - a2));
|
|
||||||
dis[1] = min(abs(a1 - a3), n - abs(a1 - a3));
|
|
||||||
dis[2] = min(abs(a3 - a2), n - abs(a3 - a2));
|
|
||||||
|
|
||||||
sort(dis.begin(), dis.end());
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
if (dis[0] < k) result += (k - dis[0]);
|
|
||||||
if (dis[1] < k) result += (k - dis[1]);
|
|
||||||
|
|
||||||
cout << result << endl;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Java代码:
|
|
||||||
|
|
||||||
```Java
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Scanner scanner = new Scanner(System.in);
|
|
||||||
int t = scanner.nextInt();
|
|
||||||
|
|
||||||
while (t-- > 0) {
|
|
||||||
int n = scanner.nextInt();
|
|
||||||
int k = scanner.nextInt();
|
|
||||||
int a1 = scanner.nextInt();
|
|
||||||
int a2 = scanner.nextInt();
|
|
||||||
int a3 = scanner.nextInt();
|
|
||||||
if (k * 3 > n) {
|
|
||||||
System.out.println(-1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Integer> dis = new ArrayList<>(3);
|
|
||||||
dis.add(Math.min(Math.abs(a1 - a2), n - Math.abs(a1 - a2)));
|
|
||||||
dis.add(Math.min(Math.abs(a1 - a3), n - Math.abs(a1 - a3)));
|
|
||||||
dis.add(Math.min(Math.abs(a3 - a2), n - Math.abs(a3 - a2)));
|
|
||||||
|
|
||||||
Collections.sort(dis);
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
if (dis.get(0) < k) result += (k - dis.get(0));
|
|
||||||
if (dis.get(1) < k) result += (k - dis.get(1));
|
|
||||||
|
|
||||||
System.out.println(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,122 +0,0 @@
|
|||||||
|
|
||||||
# 扑克牌同花顺
|
|
||||||
|
|
||||||
首先我们要定义一个结构体,来存放我们的数据
|
|
||||||
|
|
||||||
`map<花色,{同一花色牌集合,同一花色的牌对应的牌数量}>`
|
|
||||||
|
|
||||||
再遍历 每一个花色下,每一个牌 的数量
|
|
||||||
|
|
||||||
代码如下详细注释:
|
|
||||||
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include<bits/stdc++.h>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
string cards[] = {"H","S","D","C"};
|
|
||||||
typedef long long ll;
|
|
||||||
struct color
|
|
||||||
{
|
|
||||||
set<int> st; // 同一花色 牌的集合
|
|
||||||
map<int, ll> cnt; // 同一花色 牌对应的数量
|
|
||||||
};
|
|
||||||
unordered_map<string, color> umap;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
int x, y;
|
|
||||||
string card;
|
|
||||||
cin >> x >> y >> card;
|
|
||||||
umap[card].st.insert(x);
|
|
||||||
umap[card].cnt[x] += y;
|
|
||||||
}
|
|
||||||
ll sum = 0;
|
|
||||||
// 遍历每一个花色
|
|
||||||
for (string cardOne : cards) {
|
|
||||||
color colorOne = umap[cardOne];
|
|
||||||
// 遍历 同花色 每一个牌
|
|
||||||
for (int number : colorOne.st) {
|
|
||||||
ll numberCount = colorOne.cnt[number]; // 获取牌为number的数量是 numberCount
|
|
||||||
|
|
||||||
// 统计 number 到 number + 4 都是否有牌,用cal 把 number 到number+4 的数量记下来
|
|
||||||
ll cal = numberCount;
|
|
||||||
for (int j = number + 1; j <= number + 4; j++) cal = min(cal, colorOne.cnt[j]);
|
|
||||||
// 统计结果
|
|
||||||
sum += cal;
|
|
||||||
// 把统计过的同花顺数量减下去
|
|
||||||
for (int j = number + 1; j <= number + 4; j++) colorOne.cnt[j] -= cal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cout << sum << endl;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Java代码如下:
|
|
||||||
|
|
||||||
```Java
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
static String[] cards = {"H", "S", "D", "C"}; // 花色数组
|
|
||||||
|
|
||||||
static class Color {
|
|
||||||
Set<Integer> st; // 同一花色牌的集合
|
|
||||||
Map<Integer, Long> cnt; // 同一花色牌对应的数量
|
|
||||||
|
|
||||||
Color() {
|
|
||||||
st = new HashSet<>(); // 初始化集合
|
|
||||||
cnt = new HashMap<>(); // 初始化映射
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Map<String, Color> umap = new HashMap<>(); // 用于存储每种花色对应的Color对象
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Scanner scanner = new Scanner(System.in);
|
|
||||||
int n = scanner.nextInt(); // 读取牌的数量
|
|
||||||
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
int x = scanner.nextInt(); // 读取牌的值
|
|
||||||
int y = scanner.nextInt(); // 读取牌的数量
|
|
||||||
String card = scanner.next(); // 读取牌的花色
|
|
||||||
|
|
||||||
umap.putIfAbsent(card, new Color()); // 如果不存在该花色,则创建一个新的Color对象
|
|
||||||
umap.get(card).st.add(x); // 将牌的值加入集合
|
|
||||||
umap.get(card).cnt.put(x, umap.get(card).cnt.getOrDefault(x, 0L) + y); // 更新牌的数量
|
|
||||||
}
|
|
||||||
|
|
||||||
long sum = 0; // 结果累加器
|
|
||||||
|
|
||||||
// 遍历每一种花色
|
|
||||||
for (String cardOne : cards) {
|
|
||||||
Color colorOne = umap.getOrDefault(cardOne, new Color()); // 获取对应花色的Color对象
|
|
||||||
|
|
||||||
// 遍历同花色的每一张牌
|
|
||||||
for (int number : colorOne.st) {
|
|
||||||
long numberCount = colorOne.cnt.get(number); // 获取当前牌的数量
|
|
||||||
|
|
||||||
// 计算从当前牌到number+4的最小数量
|
|
||||||
long cal = numberCount;
|
|
||||||
for (int j = number + 1; j <= number + 4; j++) {
|
|
||||||
cal = Math.min(cal, colorOne.cnt.getOrDefault(j, 0L)); // 更新cal为最小值
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将结果累加到sum
|
|
||||||
sum += cal;
|
|
||||||
|
|
||||||
// 将统计过的同花顺数量减去
|
|
||||||
for (int j = number + 1; j <= number + 4; j++) {
|
|
||||||
colorOne.cnt.put(j, colorOne.cnt.getOrDefault(j, 0L) - cal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println(sum); // 输出结果
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,102 +0,0 @@
|
|||||||
|
|
||||||
# 149. 好数组
|
|
||||||
|
|
||||||
贪心思路:
|
|
||||||
|
|
||||||
整体思路是移动到中间位置(中位数),一定是 移动次数最小的。
|
|
||||||
|
|
||||||
有一个数可以不改变,对数组排序之后, 最小数 和 最大数 一定是移动次数最多的,所以分别保留最小 和 最大的不变。
|
|
||||||
|
|
||||||
中间可能有两个位置,所以要计算中间偏前 和 中间偏后的
|
|
||||||
|
|
||||||
代码如下:
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include<bits/stdc++.h>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
vector<long> arr(n);
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
cin >> arr[i];
|
|
||||||
}
|
|
||||||
sort(arr.begin(), arr.end());
|
|
||||||
|
|
||||||
if (arr[0] == arr[n - 1]) {
|
|
||||||
cout << 1 << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
long cnt = 0L;
|
|
||||||
long cnt1 = 0L;
|
|
||||||
|
|
||||||
// 如果要保留一个不改变,要不不改最小的,要不不改最大的。
|
|
||||||
|
|
||||||
// 取中间偏前的位置
|
|
||||||
long mid = arr[(n - 2) / 2];
|
|
||||||
|
|
||||||
// 不改最大的
|
|
||||||
for (int i = 0; i < n - 1; i++) {
|
|
||||||
cnt += abs(arr[i] - mid);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 取中间偏后的位置
|
|
||||||
mid = arr[n / 2];
|
|
||||||
|
|
||||||
// 不改最小的
|
|
||||||
for (int i = 1; i < n; i++) {
|
|
||||||
cnt1 += abs(arr[i] - mid);
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << min(cnt, cnt1) << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Java代码如下:
|
|
||||||
|
|
||||||
```Java
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Scanner scanner = new Scanner(System.in);
|
|
||||||
int n = scanner.nextInt();
|
|
||||||
long[] arr = new long[n];
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
arr[i] = scanner.nextLong();
|
|
||||||
}
|
|
||||||
Arrays.sort(arr);
|
|
||||||
|
|
||||||
if (arr[0] == arr[n - 1]) {
|
|
||||||
System.out.println(1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
long cnt = 0L;
|
|
||||||
long cnt1 = 0L;
|
|
||||||
|
|
||||||
// 如果要保留一个不改变,要不不改最小的,要不不改最大的。
|
|
||||||
|
|
||||||
// 取中间偏前的位置
|
|
||||||
long mid = arr[(n - 2) / 2];
|
|
||||||
|
|
||||||
// 不改最大的
|
|
||||||
for (int i = 0; i < n - 1; i++) {
|
|
||||||
cnt += Math.abs(arr[i] - mid);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 取中间偏后的位置
|
|
||||||
mid = arr[n / 2];
|
|
||||||
|
|
||||||
// 不改最小的
|
|
||||||
for (int i = 1; i < n; i++) {
|
|
||||||
cnt1 += Math.abs(arr[i] - mid);
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println(Math.min(cnt, cnt1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,66 +0,0 @@
|
|||||||
|
|
||||||
# 150. 极长连续段的权值
|
|
||||||
|
|
||||||
动态规划,枚举最后边节点的情况:
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
string s;
|
|
||||||
cin >> s;
|
|
||||||
|
|
||||||
long long result = 1;
|
|
||||||
long long a = 1;
|
|
||||||
|
|
||||||
for (int i = 1; i < n; ++i) {
|
|
||||||
// 加上本身长度为1的子串
|
|
||||||
if (s[i] == s[i - 1]) {
|
|
||||||
a += 1;
|
|
||||||
result += a;
|
|
||||||
// 以最右节点为终点,每个子串的级长连续段都+1,再加本身长度为1的子串
|
|
||||||
} else {
|
|
||||||
a = a + i + 1;
|
|
||||||
result += a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cout << result << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Java代码如下:
|
|
||||||
|
|
||||||
```Java
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Scanner scanner = new Scanner(System.in);
|
|
||||||
int n = scanner.nextInt();
|
|
||||||
String s = scanner.next();
|
|
||||||
|
|
||||||
long result = 1;
|
|
||||||
long a = 1;
|
|
||||||
|
|
||||||
for (int i = 1; i < n; ++i) {
|
|
||||||
// 加上本身长度为1的子串
|
|
||||||
if (s.charAt(i) == s.charAt(i - 1)) {
|
|
||||||
a += 1;
|
|
||||||
result += a;
|
|
||||||
// 以最右节点为终点,每个子串的级长连续段都+1,再加本身长度为1的子串
|
|
||||||
} else {
|
|
||||||
a = a + i + 1;
|
|
||||||
result += a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,127 +0,0 @@
|
|||||||
# 151. 手机流畅运行的秘密
|
|
||||||
|
|
||||||
[题目链接](https://kamacoder.com/problempage.php?pid=1229)
|
|
||||||
|
|
||||||
先运行 能留下电量多的 任务,才能有余电运行其他任务。
|
|
||||||
|
|
||||||
任务1,1:10 ,运行完 能留下 9个电
|
|
||||||
|
|
||||||
任务2,2:12,运行完 能留下 10个电
|
|
||||||
|
|
||||||
任务3,3:10,运行完 能留下 7个电。
|
|
||||||
|
|
||||||
运行顺序: 任务2 -> 任务1 -> 任务3
|
|
||||||
|
|
||||||
按照 最低初始电量 - 耗电量,从大到小排序。
|
|
||||||
|
|
||||||
计算总电量,需要 从小到大 遍历, 不断取 总电量 + 任务耗电量 与 任务最低初始电量 的最大值。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include<bits/stdc++.h>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
bool cmp(const pair<int,int>& taskA, const pair<int,int>& taskB) {
|
|
||||||
return (taskA.second - taskA.first) < (taskB.second - taskB.first);
|
|
||||||
}
|
|
||||||
int main() {
|
|
||||||
string str, tmp;
|
|
||||||
vector<pair<int,int>> tasks;
|
|
||||||
|
|
||||||
//处理输入
|
|
||||||
getline(cin, str);
|
|
||||||
stringstream ss(str);
|
|
||||||
while (getline(ss, tmp, ',')) {
|
|
||||||
int p = tmp.find(":");
|
|
||||||
string a = tmp.substr(0, p);
|
|
||||||
string b = tmp.substr(p + 1);
|
|
||||||
tasks.push_back({stoi(a), stoi(b)});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 按照差值从小到大排序
|
|
||||||
sort(tasks.begin(), tasks.end(), cmp);
|
|
||||||
|
|
||||||
// 收集结果
|
|
||||||
int result = 0;
|
|
||||||
for (int i = 0 ; i < tasks.size(); i++) {
|
|
||||||
result = max(result + tasks[i].first, tasks[i].second);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = result <= 4800 ? result : -1;
|
|
||||||
cout << result << endl;
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Java版本:
|
|
||||||
|
|
||||||
```Java
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Scanner sc = new Scanner(System.in);
|
|
||||||
String str = sc.nextLine();
|
|
||||||
String[] tasksArray = str.split(",");
|
|
||||||
List<Pair> tasks = Arrays.stream(tasksArray)
|
|
||||||
.map(task -> {
|
|
||||||
String[] parts = task.split(":");
|
|
||||||
return new Pair(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]));
|
|
||||||
})
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
// 按照差值从小到大排序
|
|
||||||
Collections.sort(tasks, (taskA, taskB) ->
|
|
||||||
(taskA.second - taskA.first) - (taskB.second - taskB.first)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 收集结果
|
|
||||||
int result = 0;
|
|
||||||
for (Pair task : tasks) {
|
|
||||||
result = Math.max(result + task.first, task.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = result <= 4800 ? result : -1;
|
|
||||||
System.out.println(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Pair {
|
|
||||||
int first;
|
|
||||||
int second;
|
|
||||||
|
|
||||||
Pair(int first, int second) {
|
|
||||||
this.first = first;
|
|
||||||
this.second = second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Python版本:
|
|
||||||
|
|
||||||
```python
|
|
||||||
def main():
|
|
||||||
import sys
|
|
||||||
input = sys.stdin.read
|
|
||||||
|
|
||||||
str = input().strip()
|
|
||||||
tasks = []
|
|
||||||
for tmp in str.split(','):
|
|
||||||
a, b = map(int, tmp.split(':'))
|
|
||||||
tasks.append((a, b))
|
|
||||||
|
|
||||||
# 按照差值从小到大排序
|
|
||||||
tasks.sort(key=lambda task: task[1] - task[0])
|
|
||||||
|
|
||||||
# 收集结果
|
|
||||||
result = 0
|
|
||||||
for task in tasks:
|
|
||||||
result = max(result + task[0], task[1])
|
|
||||||
|
|
||||||
result = result if result <= 4800 else -1
|
|
||||||
print(result)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
```
|
|
@ -1,121 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
# 152. 小米手机通信校准
|
|
||||||
|
|
||||||
[题目链接](https://kamacoder.com/problempage.php?pid=1230)
|
|
||||||
|
|
||||||
一道模拟题,但比较考察 代码能力。
|
|
||||||
|
|
||||||
遍历去找 里 freq 最近的 freg就好, 需要记录刚遍历过的的freg和 loss,因为可能有 相邻一样的 freg。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <bits/stdc++.h>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int freq;
|
|
||||||
cin >> freq;
|
|
||||||
string data;
|
|
||||||
double result = 0;
|
|
||||||
int last_freg = 0; // 记录上一个 freg
|
|
||||||
int last_loss = 0; // 记录上一个loss
|
|
||||||
while(cin >> data) {
|
|
||||||
int index = data.find(':');
|
|
||||||
int freg = stoi(data.substr(0, index)); // 获取 freg 和 loss
|
|
||||||
int loss = stoi(data.substr(index + 1));
|
|
||||||
// 两遍一样
|
|
||||||
if(abs(freg - freq) == abs(last_freg - freq)) {
|
|
||||||
result = (double)(last_loss + loss)/2.0;
|
|
||||||
} // 否则更新最新的result
|
|
||||||
else if(abs(freg - freq) < abs(last_freg - freq)){
|
|
||||||
result = (double)loss;
|
|
||||||
}
|
|
||||||
last_freg = freg;
|
|
||||||
last_loss = loss;
|
|
||||||
}
|
|
||||||
printf("%.1lf\n", result);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Java 版本:
|
|
||||||
|
|
||||||
```Java
|
|
||||||
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Scanner sc = new Scanner(System.in);
|
|
||||||
int freq = sc.nextInt();
|
|
||||||
sc.nextLine(); // 读取换行符
|
|
||||||
|
|
||||||
String inputLine = sc.nextLine(); // 读取包含所有后续输入的行
|
|
||||||
String[] data = inputLine.split(" "); // 根据空格分割输入
|
|
||||||
|
|
||||||
double result = 0;
|
|
||||||
int lastFreq = 0; // 记录上一个 freg
|
|
||||||
int lastLoss = 0; // 记录上一个 loss
|
|
||||||
|
|
||||||
for (String entry : data) {
|
|
||||||
int index = entry.indexOf(':');
|
|
||||||
int freg = Integer.parseInt(entry.substring(0, index)); // 获取 freg 和 loss
|
|
||||||
int loss = Integer.parseInt(entry.substring(index + 1));
|
|
||||||
|
|
||||||
// 两遍一样
|
|
||||||
if (Math.abs(freg - freq) == Math.abs(lastFreq - freq)) {
|
|
||||||
result = (double) (lastLoss + loss) / 2.0;
|
|
||||||
}
|
|
||||||
// 否则更新最新的 result
|
|
||||||
else if (Math.abs(freg - freq) < Math.abs(lastFreq - freq)) {
|
|
||||||
result = (double) loss;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastFreq = freg;
|
|
||||||
lastLoss = loss;
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.printf("%.1f\n", result);
|
|
||||||
sc.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Python版本:
|
|
||||||
|
|
||||||
```python
|
|
||||||
def main():
|
|
||||||
import sys
|
|
||||||
input = sys.stdin.read
|
|
||||||
data = input().split()
|
|
||||||
|
|
||||||
freq = int(data[0])
|
|
||||||
result = 0
|
|
||||||
last_freg = 0 # 记录上一个 freg
|
|
||||||
last_loss = 0 # 记录上一个 loss
|
|
||||||
|
|
||||||
for i in range(1, len(data)):
|
|
||||||
item = data[i]
|
|
||||||
index = item.find(':')
|
|
||||||
freg = int(item[:index]) # 获取 freg 和 loss
|
|
||||||
loss = int(item[index + 1:])
|
|
||||||
|
|
||||||
# 两遍一样
|
|
||||||
if abs(freg - freq) == abs(last_freg - freq):
|
|
||||||
result = (last_loss + loss) / 2.0
|
|
||||||
# 否则更新最新的 result
|
|
||||||
elif abs(freg - freq) < abs(last_freg - freq):
|
|
||||||
result = loss
|
|
||||||
|
|
||||||
last_freg = freg
|
|
||||||
last_loss = loss
|
|
||||||
|
|
||||||
print(f"{result:.1f}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
@ -1,95 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
# 权值优势路径计数
|
|
||||||
|
|
||||||
[题目链接](https://kamacoder.com/problempage.php?pid=1231)
|
|
||||||
|
|
||||||
1、构建二叉树:首先根据层序遍历的序列构建二叉树。这可以通过使用队列来实现,队列中存储当前节点及其索引,确保可以正确地将子节点添加到父节点下。
|
|
||||||
|
|
||||||
2、路径遍历:使用深度优先搜索(DFS)遍历所有从根到叶子的路径。在遍历过程中,维护一个计数器跟踪当前路径中权值为 1 和权值为 0 的节点的数量。
|
|
||||||
|
|
||||||
3、计数满足条件的路径:每当到达一个叶子节点时,检查当前路径的权值 1 的节点数量是否比权值 0 的节点数量多 1。如果满足,递增一个全局计数器。
|
|
||||||
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
struct TreeNode {
|
|
||||||
int val;
|
|
||||||
TreeNode *left, *right;
|
|
||||||
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// DFS遍历二叉树,并计算满足条件的路径数量
|
|
||||||
void countPaths(TreeNode* node, int count1, int count0, int& result) {
|
|
||||||
if (!node) return;
|
|
||||||
|
|
||||||
// 更新当前路径中1和0的数量
|
|
||||||
node->val == 1 ? count1++ : count0++;
|
|
||||||
|
|
||||||
// 检查当前节点是否为叶子节点
|
|
||||||
if (!node->left && !node->right) {
|
|
||||||
// 检查1的数量是否比0的数量多1
|
|
||||||
if (count1 == count0 + 1) {
|
|
||||||
result++;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 递归访问左右子节点
|
|
||||||
countPaths(node->left, count1, count0, result);
|
|
||||||
countPaths(node->right, count1, count0, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int N;
|
|
||||||
cin >> N;
|
|
||||||
|
|
||||||
vector<int> nums(N);
|
|
||||||
for (int i = 0; i < N; ++i) {
|
|
||||||
cin >> nums[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nums.empty()) {
|
|
||||||
cout << 0 << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据层序遍历的输入构建二叉树
|
|
||||||
queue<TreeNode*> q;
|
|
||||||
TreeNode* root = new TreeNode(nums[0]);
|
|
||||||
q.push(root);
|
|
||||||
int index = 1;
|
|
||||||
|
|
||||||
while (!q.empty() && index < N) {
|
|
||||||
TreeNode* node = q.front();
|
|
||||||
q.pop();
|
|
||||||
|
|
||||||
if (index < N && nums[index] != -1) {
|
|
||||||
node->left = new TreeNode(nums[index]);
|
|
||||||
q.push(node->left);
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
|
|
||||||
if (index < N && nums[index] != -1) {
|
|
||||||
node->right = new TreeNode(nums[index]);
|
|
||||||
q.push(node->right);
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算满足条件的路径数
|
|
||||||
int result = 0;
|
|
||||||
countPaths(root, 0, 0, result);
|
|
||||||
|
|
||||||
cout << result << endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,68 +0,0 @@
|
|||||||
|
|
||||||
# 序列中位数
|
|
||||||
|
|
||||||
[题目链接](https://kamacoder.com/problempage.php?pid=1232)
|
|
||||||
|
|
||||||
注意给的数组默认不是有序的!
|
|
||||||
|
|
||||||
模拟题,排序之后,取中位数,然后按照b数组 删 a数组中元素,再取中位数。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include<bits/stdc++.h>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
// 计算并返回中位数
|
|
||||||
double findMedian(vector<int>& nums) {
|
|
||||||
int n = nums.size();
|
|
||||||
if (n % 2 == 1) {
|
|
||||||
return nums[n / 2]; // 奇数长度,返回中间的元素
|
|
||||||
} else {
|
|
||||||
// 偶数长度,返回中间两个元素的平均值
|
|
||||||
return (nums[n / 2] + nums[n / 2 - 1]) / 2.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main(){
|
|
||||||
int t;
|
|
||||||
cin >> t;
|
|
||||||
while(t--){
|
|
||||||
int n;
|
|
||||||
cin>> n;
|
|
||||||
vector<int> a(n);
|
|
||||||
vector<int> b(n - 1);
|
|
||||||
for(int i = 0; i < n; i++){
|
|
||||||
cin >> a[i];
|
|
||||||
}
|
|
||||||
for(int i = 0; i < n - 1; i++){
|
|
||||||
cin >> b[i];
|
|
||||||
}
|
|
||||||
vector<int> nums = a;
|
|
||||||
vector<double> answers;
|
|
||||||
|
|
||||||
sort(nums.begin(), nums.end());
|
|
||||||
|
|
||||||
// 把中位数放进结果集
|
|
||||||
answers.push_back(findMedian(nums));
|
|
||||||
|
|
||||||
for(int i = 0; i < n - 1; i++){
|
|
||||||
|
|
||||||
int target = a[b[i]];
|
|
||||||
// 删除目标值
|
|
||||||
nums.erase(find(nums.begin(), nums.end(), target));
|
|
||||||
// 把中位数放进结果集
|
|
||||||
answers.push_back(findMedian(nums));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto answer : answers){
|
|
||||||
// 判断是否是整数
|
|
||||||
if(answer == (int)answer) printf("%d ", (int)answer);
|
|
||||||
else printf("%.1f ", answer);
|
|
||||||
}
|
|
||||||
cout << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,106 +0,0 @@
|
|||||||
|
|
||||||
# 最小化频率的删除代价
|
|
||||||
|
|
||||||
[题目链接](https://kamacoder.com/problempage.php?pid=1233)
|
|
||||||
|
|
||||||
计数和排序:
|
|
||||||
|
|
||||||
* 使用 map 或 unordered_map 对数组 a 中每个元素出现的次数进行统计。
|
|
||||||
* 将统计结果存入一个 vector<pair<int, int>>,其中 pair 的第一个元素是元素的出现次数,第二个元素是元素本身。
|
|
||||||
* 按出现次数从大到小排序这个 vector。
|
|
||||||
|
|
||||||
确定最小 f(a):
|
|
||||||
|
|
||||||
* 从最大出现次数开始尝试减少 f(a)。为此,从最高频次的元素开始逐步向下考虑较少出现的元素,计算达到更低 f(a) 所需删除的元素数量。
|
|
||||||
* 使用一个累加器 count 来记录需要删除的元素数量,直到这个数量超过允许的最大删除数量 k 或恰好等于 k。在此过程中,尽量使 f(a) 达到最小。
|
|
||||||
|
|
||||||
计算达到 f(a) 的代价:
|
|
||||||
|
|
||||||
* 计算完成后,需要确定达到最小 f(a) 的确切代价。首先,为每个元素确定在不超过 k 的前提下可以删除的最大数量,以使得 f(a) 最小。
|
|
||||||
* 对于每个元素,如果它的数量超过了新的 f(a),则计算减少到 f(a) 所需删除的具体元素数,记录下来。
|
|
||||||
|
|
||||||
计算具体删除代价:
|
|
||||||
|
|
||||||
* 遍历原数组,对于每个需要删除的元素,根据其位置累加删除代价。每删除一个元素,相应地减少其在删除列表中的计数。当某元素需要删除的数量减至 0 时,从删除列表中移除该元素。
|
|
||||||
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int n, k;
|
|
||||||
cin >> n >> k;
|
|
||||||
|
|
||||||
vector<int> a(n);
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
cin >> a[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
unordered_map<int, int> umap; // 使用map来统计每个元素的出现频率
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
umap[a[i]]++; // 统计每个元素的出现次数
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<pair<int, int>> table;
|
|
||||||
for (auto& pair : umap) {
|
|
||||||
table.push_back({pair.second, pair.first}); // 将元素和其频率作为一个pair放入table中
|
|
||||||
}
|
|
||||||
|
|
||||||
sort(table.begin(), table.end(), greater<>()); // 将table按照频率从大到小排序
|
|
||||||
|
|
||||||
int count = 0; // 用来计算已经删除的元素总数
|
|
||||||
int minVal = table[0].first; // 从最高频率开始
|
|
||||||
for (int i = 0; i < table.size(); ++i) {
|
|
||||||
int freq = table[i].first;
|
|
||||||
count += (minVal - freq) * i; // 累加删除元素的代价
|
|
||||||
if (count > k) break; // 如果超过了k,停止循环
|
|
||||||
else if (count == k) {
|
|
||||||
minVal = freq;
|
|
||||||
break;
|
|
||||||
} else minVal = freq;
|
|
||||||
}
|
|
||||||
if (count < k) {
|
|
||||||
int addDel = (k - count) / table.size(); // 如果删除的代价还没达到k,计算还可以进一步减少的频率
|
|
||||||
minVal -= addDel; // 减少相应的频率
|
|
||||||
}
|
|
||||||
|
|
||||||
if (minVal < 0) {
|
|
||||||
minVal = 0; // 确保最小频率值不小于0
|
|
||||||
}
|
|
||||||
|
|
||||||
unordered_map<int, int> deleteList; // 用来存储需要删除的元素及其数量
|
|
||||||
for (auto& elem : table) {
|
|
||||||
int num = elem.first;
|
|
||||||
int ind = elem.second;
|
|
||||||
if (num > minVal) {
|
|
||||||
deleteList[ind] = num - minVal; // 如果元素频率大于最小值,计算需要删除的数量
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int cost = 0; // 计算总的删除代价
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
if (deleteList.find(a[i]) != deleteList.end()) {
|
|
||||||
cost += i + 1; // 删除的代价是元素的索引+1
|
|
||||||
deleteList[a[i]]--; // 删除一个元素
|
|
||||||
if (deleteList[a[i]] == 0) {
|
|
||||||
deleteList.erase(a[i]); // 如果元素已经全部删除,从列表中移除
|
|
||||||
if (deleteList.empty()) {
|
|
||||||
break; // 如果没有元素需要删除了,结束循环
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << minVal << " " << cost << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,68 +0,0 @@
|
|||||||
|
|
||||||
# 勇敢牛牛战斗序列
|
|
||||||
|
|
||||||
[题目链接](https://kamacoder.com/problempage.php?pid=1234)
|
|
||||||
|
|
||||||
贪心思路,对数组从小到大排序之后,先取最右边,再取最左边,循环反复。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include<bits/stdc++.h>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
vector<int> a(n); // 使用 vector 存储整数数组
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
cin >> a[i]; // 读取数组
|
|
||||||
}
|
|
||||||
sort(a.begin(), a.end()); // 对数组进行排序
|
|
||||||
|
|
||||||
long long ans = 0; // 使用 long long 存储结果,以防溢出
|
|
||||||
int cur = 0;
|
|
||||||
int left = 0, right = n - 1;
|
|
||||||
while (left <= right) {
|
|
||||||
if (cur < a[right]) {
|
|
||||||
ans += a[right] - cur;
|
|
||||||
}
|
|
||||||
cur = a[left];
|
|
||||||
right--;
|
|
||||||
left++;
|
|
||||||
}
|
|
||||||
cout << ans << endl; // 输出结果
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```Java
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Scanner sc = new Scanner(System.in);
|
|
||||||
int n = sc.nextInt();
|
|
||||||
int[] a = new int[n];
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
a[i] = sc.nextInt();
|
|
||||||
}
|
|
||||||
Arrays.sort(a);
|
|
||||||
long ans = 0;
|
|
||||||
int cur = 0;
|
|
||||||
int left = 0, right = a.length - 1;
|
|
||||||
while (left <= right) {
|
|
||||||
if (cur < a[right]) {
|
|
||||||
ans = ans + a[right] - cur;
|
|
||||||
}
|
|
||||||
cur = a[left];
|
|
||||||
right--;
|
|
||||||
left++;
|
|
||||||
}
|
|
||||||
System.out.println(ans);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,59 +0,0 @@
|
|||||||
|
|
||||||
# 最大化密码复杂度
|
|
||||||
|
|
||||||
[题目链接](https://kamacoder.com/problempage.php?pid=1235)
|
|
||||||
|
|
||||||
注意**边界处理**,对于字符串的首尾位置,需要特别处理,因为它们只有一个相邻字符。
|
|
||||||
* 遍历字符串 s,寻找 '?' 字符。
|
|
||||||
* 对于每个 '?' 字符,选择一个字符填充,使其与前后字符都不同。这样做的目的是最大化密码的复杂度,即尽可能使相邻的字符不同。
|
|
||||||
* 如果 '?' 是第一个或最后一个字符,或者无法找到与前后都不同的字符,选择与前一个或后一个字符不同的字符。
|
|
||||||
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int n, m;
|
|
||||||
string s;
|
|
||||||
cin >> n >> m >> s;
|
|
||||||
|
|
||||||
if (n == 1) {
|
|
||||||
cout << 0 << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 统一处理包括左右字符的情况
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
if (s[i] == '?') {
|
|
||||||
bool found = false;
|
|
||||||
for (char j = 'a'; j < 'a' + m; ++j) {
|
|
||||||
// 避免第一个字符 和 最后一个字符,因为两个字符只有一个相邻字符,没有左右相邻字符
|
|
||||||
if ((i == 0 || s[i - 1] != j) && (i == n - 1 || s[i + 1] != j)) {
|
|
||||||
s[i] = j;
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 如果没有找到合适的字符,就和附近字符保持一致
|
|
||||||
if (!found) {
|
|
||||||
if (i > 0) s[i] = s[i - 1];
|
|
||||||
else s[i] = s[i + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算结果
|
|
||||||
int result = 0;
|
|
||||||
for (int i = 0; i < n - 1; ++i) {
|
|
||||||
if (s[i] != s[i + 1]) result++;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << result << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,50 +0,0 @@
|
|||||||
|
|
||||||
# 同余方程
|
|
||||||
|
|
||||||
题目链接:https://kamacoder.com/problempage.php?pid=1236
|
|
||||||
|
|
||||||
我们需要求出满足以下条件的最小正整数 x:`ax≡1 (mod b)`
|
|
||||||
|
|
||||||
这意味着我们需要找到 x 使得 ax 除以 b 的余数是 1。这个问题实际上是一个典型的 模反元素 问题。
|
|
||||||
|
|
||||||
解题思路:
|
|
||||||
|
|
||||||
* 为了求出最小的 x,我们可以使用 扩展欧几里得算法 来求出 a 对模 b 的逆元。
|
|
||||||
* 这个算法能够求解 ax + by = gcd(a, b) 的一组整数解 (x, y),而在 gcd(a, b) = 1 的情况下,x 即为所求的模逆元。
|
|
||||||
* 扩展欧几里得算法:扩展欧几里得算法可以通过递归或者迭代的方式实现。
|
|
||||||
|
|
||||||
下面给出C++代码实现:
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
// 扩展欧几里得:计算 ax + by = gcd(a, b) 的解
|
|
||||||
long long extended_gcd(long long a, long long b, long long &x, long long &y) {
|
|
||||||
if (b == 0) {
|
|
||||||
x = 1;
|
|
||||||
y = 0;
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
long long x1, y1;
|
|
||||||
long long gcd = extended_gcd(b, a % b, x1, y1);
|
|
||||||
x = y1;
|
|
||||||
y = x1 - (a / b) * y1;
|
|
||||||
return gcd;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
long long a, b;
|
|
||||||
cin >> a >> b;
|
|
||||||
|
|
||||||
long long x, y;
|
|
||||||
long long gcd = extended_gcd(a, b, x, y);
|
|
||||||
|
|
||||||
// 由于我们只需要模 b 的正整数解,所以我们要保证 x 是正数
|
|
||||||
x = (x % b + b) % b;
|
|
||||||
|
|
||||||
cout << x << endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,62 +0,0 @@
|
|||||||
|
|
||||||
# 大整数乘法
|
|
||||||
|
|
||||||
题目链接:https://kamacoder.com/problempage.php?pid=1237
|
|
||||||
|
|
||||||
思路:
|
|
||||||
|
|
||||||
我们可以使用模拟手算乘法的方法,即「逐位相乘累加」,对于每一位的乘法结果,我们将其加到相应的结果位置上。最终将累加的结果输出。
|
|
||||||
|
|
||||||
具体步骤:
|
|
||||||
|
|
||||||
* 初始化结果数组:结果数组的长度应该是两个数字长度之和,因为最大长度的结果不会超过这个长度。
|
|
||||||
* 逐位相乘:从右往左遍历两个字符串的每一位,逐位相乘,并加到结果数组的相应位置。
|
|
||||||
* 处理进位:在每一步累加之后处理进位,保证每个位置的值小于10。
|
|
||||||
|
|
||||||
将结果数组转化为字符串:从结果数组的最高位开始,忽略前导零,然后将数组转化为字符串。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
string multiply(string num1, string num2) {
|
|
||||||
int len1 = num1.size();
|
|
||||||
int len2 = num2.size();
|
|
||||||
vector<int> result(len1 + len2, 0);
|
|
||||||
|
|
||||||
// 逐位相乘
|
|
||||||
for (int i = len1 - 1; i >= 0; i--) {
|
|
||||||
for (int j = len2 - 1; j >= 0; j--) {
|
|
||||||
int mul = (num1[i] - '0') * (num2[j] - '0');
|
|
||||||
int sum = mul + result[i + j + 1];
|
|
||||||
|
|
||||||
result[i + j + 1] = sum % 10;
|
|
||||||
result[i + j] += sum / 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将结果转换为字符串,跳过前导零
|
|
||||||
string product;
|
|
||||||
for (int num : result) {
|
|
||||||
if (!(product.empty() && num == 0)) { // 跳过前导零
|
|
||||||
product.push_back(num + '0');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return product.empty() ? "0" : product;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
string num1, num2;
|
|
||||||
cin >> num1 >> num2;
|
|
||||||
|
|
||||||
string result = multiply(num1, num2);
|
|
||||||
cout << result << endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,88 +0,0 @@
|
|||||||
|
|
||||||
# 二维平面上的折线段
|
|
||||||
|
|
||||||
题目链接:https://kamacoder.com/problempage.php?pid=1238
|
|
||||||
|
|
||||||
这个问题要求我们在一条折线段上,根据移动的固定距离 s 进行标记点的计算。
|
|
||||||
|
|
||||||
为了实现这一点,我们需要对折线段进行分段处理,并根据每段的长度来确定标记点的位置。
|
|
||||||
|
|
||||||
解题思路:
|
|
||||||
|
|
||||||
1. 输入与初步处理:
|
|
||||||
* 首先,读取所有点的坐标。
|
|
||||||
* 计算每一段折线的长度,并逐段累积总长度。
|
|
||||||
2. 确定标记点:
|
|
||||||
* 从起点开始,每次沿着折线段前进 s 的距离,直到到达终点。
|
|
||||||
* 对于每个标记点,根据当前段的起点和终点,计算出该点的精确坐标。
|
|
||||||
3. 输出所有标记点的坐标,格式为 x, y。
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <cmath>
|
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
// 定义一个点的结构体
|
|
||||||
struct Point {
|
|
||||||
double x, y;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 计算两点之间的距离
|
|
||||||
double distance(const Point& a, const Point& b) {
|
|
||||||
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
|
|
||||||
vector<Point> points(n);
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
cin >> points[i].x >> points[i].y;
|
|
||||||
}
|
|
||||||
|
|
||||||
double s;
|
|
||||||
cin >> s;
|
|
||||||
|
|
||||||
double total_length = 0.0;
|
|
||||||
vector<double> segment_lengths(n - 1);
|
|
||||||
|
|
||||||
// 计算每段长度和总长度
|
|
||||||
for (int i = 0; i < n - 1; i++) {
|
|
||||||
segment_lengths[i] = distance(points[i], points[i + 1]);
|
|
||||||
total_length += segment_lengths[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从起点开始标记
|
|
||||||
Point current_point = points[0];
|
|
||||||
double accumulated_distance = 0.0;
|
|
||||||
|
|
||||||
cout << fixed << setprecision(5);
|
|
||||||
cout << current_point.x << ", " << current_point.y << endl;
|
|
||||||
|
|
||||||
while (accumulated_distance + s <= total_length) {
|
|
||||||
accumulated_distance += s;
|
|
||||||
double remaining_distance = accumulated_distance;
|
|
||||||
|
|
||||||
for (int i = 0; i < n - 1; i++) {
|
|
||||||
if (remaining_distance <= segment_lengths[i]) {
|
|
||||||
double ratio = remaining_distance / segment_lengths[i];
|
|
||||||
double new_x = points[i].x + ratio * (points[i + 1].x - points[i].x);
|
|
||||||
double new_y = points[i].y + ratio * (points[i + 1].y - points[i].y);
|
|
||||||
current_point = {new_x, new_y};
|
|
||||||
cout << current_point.x << ", " << current_point.y << endl;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
remaining_distance -= segment_lengths[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,61 +0,0 @@
|
|||||||
|
|
||||||
# 讨厌鬼的组合帖子
|
|
||||||
|
|
||||||
[题目链接](https://kamacoder.com/problempage.php?pid=1239)
|
|
||||||
|
|
||||||
这个问题本质上是要找到两个数组的子集,使得这两个子集之间的差的绝对值最大。
|
|
||||||
|
|
||||||
问题可以简化为寻找两个数列之间最大可能的差的绝对值。
|
|
||||||
|
|
||||||
贪心思路如下:
|
|
||||||
|
|
||||||
计算差异,首先,我们可以计算每个帖子的点赞数和点踩数的差值 d[i] = a[i] - b[i]。这样问题就转化为选择这些差值的一个子集,使得子集中所有元素的和的绝对值最大。
|
|
||||||
|
|
||||||
遍历可能性,要使得一个数的绝对值尽可能大,可以尝试最大化这个数,或者最小化这个数(使其尽可能小于零)。我们可以分别尝试将所有正的差值加在一起,以及将所有负的差值加在一起。
|
|
||||||
|
|
||||||
计算最大吸引度:
|
|
||||||
|
|
||||||
* 将所有正的差值求和得到一个总和。
|
|
||||||
* 将所有负的差值求和得到另一个总和。
|
|
||||||
* 最后,吸引度即为这两个总和的绝对值中的较大者。
|
|
||||||
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
|
|
||||||
vector<int> a(n), b(n);
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
cin >> a[i];
|
|
||||||
}
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
cin >> b[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
long long positive_sum = 0;
|
|
||||||
long long negative_sum = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
int difference = a[i] - b[i];
|
|
||||||
if (difference > 0) {
|
|
||||||
positive_sum += difference;
|
|
||||||
} else if (difference < 0) {
|
|
||||||
negative_sum += difference;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 最大吸引度是正总和或负总和的绝对值中的较大者
|
|
||||||
cout << max(abs(positive_sum), abs(negative_sum)) << endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
|||||||
|
|
||||||
# 优秀数组
|
|
||||||
|
|
||||||
[题目链接](https://kamacoder.com/problempage.php?pid=1241)
|
|
||||||
|
|
||||||
## 解题思路
|
|
||||||
|
|
||||||
1、初始分析
|
|
||||||
|
|
||||||
- 给定一个排列 `p`,我们首先构建一个 `pos` 数组,使得 `pos[i]` 表示 `i` 在排列 `p` 中的位置。
|
|
||||||
- 我们需要判断数组 `a` 是否是一个优秀数组,即 `pos[a[i]] < pos[a[i+1]] <= pos[a[i]] + d` 对于所有 `i` 都成立。
|
|
||||||
- 我们的目标是通过最少的相邻元素交换,使得数组 `a` 不再是一个优秀数组。
|
|
||||||
|
|
||||||
2、思路
|
|
||||||
|
|
||||||
- 要使数组 `a` 不再是优秀数组,我们只需要打破条件 `pos[a[i]] < pos[a[i+1]] <= pos[a[i]] + d` 中的某一个。
|
|
||||||
- 一种简单的做法是让 `pos[a[i]]` 和 `pos[a[i+1]]` 之间的距离超过 `d`,或者直接让 `pos[a[i]] >= pos[a[i+1]]`。
|
|
||||||
|
|
||||||
3、具体方法
|
|
||||||
|
|
||||||
- 只需要考虑 `a` 中相邻元素的顺序,并判断如何交换 `p` 中相邻元素使得其顺序被打破。
|
|
||||||
- 假设我们需要在 `p` 中交换某些元素来实现上述目标,那么最小的交换次数是将 `a[i]` 和 `a[i+1]` 的位置交换。
|
|
||||||
- 如果 `pos[a[i]] + 1 == pos[a[i+1]]`,则需要一步交换。
|
|
||||||
|
|
||||||
4、特别情况
|
|
||||||
|
|
||||||
- 还需要考虑,如果通过交换相邻元素无法解决问题的情况。比如 `pos[a[i+1]]` 的位置无法移到 `pos[a[i]]` 的前面或超过 `d`。
|
|
||||||
|
|
||||||
C++代码如下:
|
|
||||||
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <climits>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int n, m, d;
|
|
||||||
cin >> n >> m >> d;
|
|
||||||
|
|
||||||
vector<int> p(n + 1);
|
|
||||||
vector<int> pos(n + 1);
|
|
||||||
|
|
||||||
// 读取排列 p,并构建位置数组 pos
|
|
||||||
for (int i = 1; i <= n; i++) {
|
|
||||||
cin >> p[i];
|
|
||||||
pos[p[i]] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<int> a(m);
|
|
||||||
for (int i = 0; i < m; i++) {
|
|
||||||
cin >> a[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
int min_operations = INT_MAX;
|
|
||||||
|
|
||||||
// 遍历数组 a 的相邻元素
|
|
||||||
for (int i = 0; i < m - 1; i++) {
|
|
||||||
int current_pos = pos[a[i]];
|
|
||||||
int next_pos = pos[a[i + 1]];
|
|
||||||
|
|
||||||
// 检查 pos[a[i]] < pos[a[i+1]] <= pos[a[i]] + d 是否成立
|
|
||||||
if (current_pos < next_pos && next_pos <= current_pos + d) {
|
|
||||||
// 计算需要的最少操作次数
|
|
||||||
int distance = next_pos - current_pos;
|
|
||||||
|
|
||||||
// Case 1: 交换 current_pos 和 next_pos
|
|
||||||
min_operations = min(min_operations, distance);
|
|
||||||
|
|
||||||
// Case 2: 如果 next_pos + d <= n,考虑使 pos[a[i+1]] 超过 pos[a[i]] + d
|
|
||||||
if (current_pos + d + 1 <= n) {
|
|
||||||
min_operations = min(min_operations, d + 1 - distance);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
min_operations = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << min_operations << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
时间复杂度为 O(m)
|
|
@ -1,81 +0,0 @@
|
|||||||
# 升序数组
|
|
||||||
|
|
||||||
[题目链接](https://kamacoder.com/problempage.php?pid=1241)
|
|
||||||
|
|
||||||
## 解题思路
|
|
||||||
|
|
||||||
贪心思路
|
|
||||||
|
|
||||||
- **计算相邻元素差值**:
|
|
||||||
- 对于数组 `a`,计算每对相邻元素的差值 `diff[i] = a[i+1] - a[i]`。
|
|
||||||
- 如果 `diff[i]` 为负数,意味着 `a[i+1]` 比 `a[i]` 小或相等,需要通过操作使 `a[i+1]` 变大。
|
|
||||||
|
|
||||||
- **确定最小操作次数**:
|
|
||||||
- 计算所有相邻元素中的最小差值 `minDifference`,即 `minDifference = min(diff[i])`。
|
|
||||||
- 如果 `minDifference` 为负数或零,则需要进行 `-minDifference + 1` 次操作,使得 `a[i+1]` 大于 `a[i]`,从而使数组严格递增。
|
|
||||||
|
|
||||||
- **实现细节**:
|
|
||||||
- 遍历数组的每对相邻元素,找出最小的差值。
|
|
||||||
- 根据最小差值,计算出最少的操作次数。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <climits>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
|
|
||||||
vector<int> arr(n); // 用于存储输入数组
|
|
||||||
vector<int> differences; // 用于存储相邻元素的差值
|
|
||||||
|
|
||||||
for(int i = 0; i < n; i++) {
|
|
||||||
cin >> arr[i];
|
|
||||||
if(i > 0) differences.push_back(arr[i] - arr[i - 1]);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int minDifference = INT_MAX;
|
|
||||||
|
|
||||||
// 寻找最小的差值
|
|
||||||
for(int diff : differences) {
|
|
||||||
if(diff < minDifference) {
|
|
||||||
minDifference = diff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果最小差值是负数或零,计算所需的操作次数
|
|
||||||
int minOperations = max(0, -minDifference + 1);
|
|
||||||
|
|
||||||
cout << minOperations << endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
关于 `-minDifference + 1` 为什么要 + 1 解释:
|
|
||||||
|
|
||||||
对于数组 `a` 中相邻的两个元素 `a[i]` 和 `a[i+1]`,我们计算它们的差值 `diff = a[i+1] - a[i]`。
|
|
||||||
|
|
||||||
- **目标**:要使 `a[i] < a[i+1]`,需要 `diff > 0`。
|
|
||||||
- 如果 `diff < 0`,说明 `a[i+1]` 比 `a[i]` 小,这时候 `a` 不是严格递增的。
|
|
||||||
- 如果 `diff = 0`,说明 `a[i+1]` 和 `a[i]` 相等,这时也不满足严格递增。
|
|
||||||
|
|
||||||
解释 `-minDifference + 1`
|
|
||||||
|
|
||||||
1. **当 `minDifference < 0` 时**:
|
|
||||||
- 假设 `minDifference` 是所有相邻差值中的最小值,并且它是一个负数。
|
|
||||||
- 例如,`minDifference = -3`,表示 `a[i+1] - a[i] = -3`,也就是 `a[i+1]` 比 `a[i]` 小 `3`。
|
|
||||||
- 要让 `a[i+1] > a[i]`,我们至少需要使 `a[i+1] - a[i]` 从 `-3` 增加到 `1`。因此需要增加 `4`,即 `(-(-3)) + 1 = 3 + 1 = 4` 次操作。
|
|
||||||
|
|
||||||
2. **当 `minDifference = 0` 时**:
|
|
||||||
- `minDifference` 等于 `0`,表示 `a[i+1] - a[i] = 0`,即 `a[i+1]` 和 `a[i]` 相等。
|
|
||||||
- 为了使 `a[i+1] > a[i]`,我们至少需要进行一次操作,使得 `a[i+1]` 大于 `a[i]`。
|
|
||||||
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
|||||||
|
|
||||||
# 最大字典序无重复串
|
|
||||||
|
|
||||||
[题目链接](https://kamacoder.com/problempage.php?pid=1243)
|
|
||||||
|
|
||||||
|
|
||||||
## 解题思路
|
|
||||||
|
|
||||||
贪心思路
|
|
||||||
|
|
||||||
为了保证字典序最大,我们优先放置字母 `b`,然后再放置字母 `a`。在放置字符时,我们还需注意不能超过连续 `k` 次相同字符:
|
|
||||||
|
|
||||||
- 如果当前已经连续放置了 `k` 次相同字符,必须切换到另一个字符。
|
|
||||||
- 每次放置字符后,相应的字符数量减少,同时更新当前字符的连续计数。
|
|
||||||
|
|
||||||
实现步骤:
|
|
||||||
|
|
||||||
- **初始化**:根据输入的 `x`, `y`, `k` 值,检查是否有可能构造出满足条件的字符串。初始化结果字符串的大小,并设置初始计数器。
|
|
||||||
- **循环放置字符**:
|
|
||||||
- 优先放置字符 `b`,如果 `b` 的数量已经足够,或者已经放置了 `k` 次字符 `b`,则放置字符 `a`。
|
|
||||||
- 如果已经放置了 `k` 次相同字符,则强制切换到另一个字符。
|
|
||||||
|
|
||||||
C++代码如下:
|
|
||||||
|
|
||||||
```CPP
|
|
||||||
#include<iostream>
|
|
||||||
#include<string>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int countA, countB, maxRepeat;
|
|
||||||
cin >> countA >> countB >> maxRepeat;
|
|
||||||
|
|
||||||
// 检查是否有可能生成满足条件的字符串
|
|
||||||
if (countA > (countB + 1) * maxRepeat || countB > (countA + 1) * maxRepeat) {
|
|
||||||
cout << -1 << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
string result(countA + countB, ' '); // 预先分配字符串大小
|
|
||||||
int currentA = 0, currentB = 0; // 当前连续 'a' 和 'b' 的计数
|
|
||||||
int pos = 0; // 当前填充位置
|
|
||||||
|
|
||||||
while (countA > 0 || countB > 0) {
|
|
||||||
// 当可以继续添加 'a' 或 'b' 且没有超过最大连续限制时
|
|
||||||
if (currentA < maxRepeat && currentB < maxRepeat) {
|
|
||||||
if (countA <= countB * maxRepeat) {
|
|
||||||
result[pos++] = 'b';
|
|
||||||
countB--;
|
|
||||||
currentB++;
|
|
||||||
currentA = 0;
|
|
||||||
} else {
|
|
||||||
result[pos++] = 'a';
|
|
||||||
countA--;
|
|
||||||
currentA++;
|
|
||||||
currentB = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 当当前字符达到最大连续限制时,切换到另一个字符
|
|
||||||
if (currentA == maxRepeat || currentB == maxRepeat) {
|
|
||||||
if (result[pos - 1] == 'a') {
|
|
||||||
result[pos++] = 'b';
|
|
||||||
countB--;
|
|
||||||
currentB = 1;
|
|
||||||
currentA = 0;
|
|
||||||
} else {
|
|
||||||
result[pos++] = 'a';
|
|
||||||
countA--;
|
|
||||||
currentA = 1;
|
|
||||||
currentB = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << result << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
时间复杂度:O(n)
|
|
Reference in New Issue
Block a user