1-压缩算法
思路
字符串
从内向外替换,
right代表从左侧开始第一个开始的’]‘位置,
left代表与当前’]‘对应的’[‘位置,
k记录’|‘位置
在遍历时,将’[‘和’|‘的位置分布入栈,当读到’]'时弹出
参考自该博客
代码
#include<iostream>
#include<string>
#include<stack>
using namespace std;
/*
思路:
从内向外替换,
right代表从左侧开始第一个开始的']'位置,
left代表与当前']'对应的'['位置,
k记录'|'位置
在遍历时,将'['和'|'的位置分布入栈,当读到']'时弹出
https://www.cnblogs.com/eisuto/archive/2020/03/11/12464469.html
*/
int main() {
string str;
cin >> str;
stack<int> s;
for (int right = 0; right < str.length(); right++) {//遍历字符串
if (str[right] == '[' || str[right] == '|') s.push(right);
if (str[right] == ']') {
int k = s.top(); s.pop();//'|'的位置
int left = s.top(); s.pop();//'['的位置
int num = stoi(str.substr(left + 1, k-left));//获得数字m
string s2;
for (int i = 0; i < num; i++) {
s2 += str.substr(k + 1, right - k-1);//将S解压缩
}
str.replace(left, right-left+1, s2);
//计算right的新位置
right = left + s2.size() - 1;
}
}
cout << str << endl;
return 0;
}
2-逛街
思路
栈
本题自己只过了50%的测试
采用单调栈的思想,在每一栋楼时,构造两个单调栈,从该处,往左往右看,分别构造单调递增栈;
最终栈的大小,即该处能看到的楼栋时;由于我采用的方法比较暴力,所以有一半数据超时,无法通过
代码
//单调栈
#include<iostream>
#include<stack>
#include<vector>
using namespace std;
int main() {
int n;
while (cin >> n) {
vector<int> ivec(n);
vector<int> ans(n);
//输入
for (int i = 0; i < n; i++) {
cin >> ivec[i];
ans[i] = 0;
}
for (int i = 0; i < n; i++) {
//从右往左看
stack<int> s_left;
stack<int> s_right;
for (int j = i - 1; j >= 0; j--) {
if (s_left.empty() || ivec[j] > s_left.top()) {
s_left.push(ivec[j]);
}
}
//从左往右看
for (int j = i + 1; j < n; j++) {
if (s_right.empty() || ivec[j] > s_right.top()) {
s_right.push(ivec[j]);
}
}
ans[i] = s_left.size() + s_right.size() + 1;
}
for (int i = 0; i < n; i++) {
cout << ans[i];
if (i < n - 1) cout << " ";
}
}
return 0;
}
3-逆序对
思路
代码
4-假期
思路
动态规划问题
参考自该博客
代码
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main() {
int n;
while (cin >> n) {
vector<int> gym(n);
vector<int> work(n);
for (int i = 0; i < n; i++) {
cin >> work[i];
}
for (int i = 0; i < n; i++) {
cin >> gym[i];
}
/*
dp[i][0]代表在第i天休息的情况下小Q最少的休息天数;
dp[i][1]代表在第i天锻炼的情况下小Q最少的休息天数;
dp[i][2]代表在第i天工作的情况下小Q最少的休息天数;
*/
vector<vector<int>> dp(n + 1, vector<int>(3,9999999));//0是休息,1是锻炼,2是工作,注意dp中的默认值要给最大,这样求min的时候,才能求到最小值,如果为0,将得不到正确结果
dp[0][0] = dp[0][1] = dp[0][2] = 0;//初始值
//遍历天数
for (int i = 1; i <= n; i++) {
if (gym[i - 1] == 1) {
//可以锻炼,选休息和工作最小的
dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]);
}
if (work[i - 1] == 1) {
//可以工作,选休息和锻炼最小的
dp[i][2] = min(dp[i - 1][0], dp[i - 1][1]);
}
//可以休息,选休息,工作和锻炼最小的
dp[i][0] = min(dp[i - 1][0], min(dp[i - 1][1], dp[i - 1][2]))+1;
}
//返回结果
int res = min(dp[n][0], min(dp[n][1], dp[n][2]));
cout << res << endl;
}
return 0;
}
5-视野争夺
思路
贪心算法——经典的区间贪心问题
对输入的顺序进行排序,左端点从小到大排序,相同时,右端点从大到小排序;
对输入的数据进行遍历,up保存当前区间的右端点,mx保存最大的右端点,两者均取第一个真眼的右端点
如果当前真眼的左端点小于up,那么更新mx;
如果当前真眼的左端点大于up,那么说明应该插上一颗真眼,sum++,且更新up值
代码
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
struct node {
int l, r;
};
bool cmp(node a, node b) {
if (a.l != b.l) return a.l < b.l;//x不等时,按x从小到大排序
else return a.r > b.r;//x相等时,按y从大到小排序
}
int main() {
int N, L;
cin >> N >> L;
vector<node> ivec(N);
for (int i = 0; i < N; i++) {
cin >> ivec[i].l >> ivec[i].r;
}
sort(ivec.begin(), ivec.end(),cmp);//排序
int up = ivec[0].r;//保存当前区间的右端点
int mx = ivec[0].r;//保存最大的右端点
int sum = 1;
if (ivec[0].l > 0) {
cout << -1 << endl;
return 0;
}
for (int i = 1; i < N; i++) {
if (ivec[i].l <= up) {//真眼左端小于up,先不插该眼,继续往前走
mx = max(ivec[i].r, mx);
if (mx >= L) {
cout << sum + 1 << endl;
return 0;
}
}
else {//发现真眼左端已大于up,说明要将之前的一个眼插入,sum++
sum++;
up = max(mx, up);
i--;//退回到上一个眼
}
}
if (mx < L) cout << -1 << endl;
else cout << sum << endl;
return 0;
}