42. 接雨水
思路:当前位置存水量等于左边最大值与右边最大值的最小值减去当前值;
```cpp
class Solution {
public:
int trap(vector<int>& height) {
if(height.size()==0) return 0;
vector<int> left(height.size(),0);
vector<int> right(height.size(),0);
left[0]=height[0];//边界条件
int res=0;
right[height.size()-1]=height[height.size()-1];//边界条件
for(int i=1;i<height.size();i++){//寻找当前位置左边最大值
left[i]=max(left[i-1],height[i]);
}
for(int i=height.size()-2;i>=0;i--){//寻找当前位置右边最大值
right[i]=max(right[i+1],height[i]);
}
for(int i=1;i<height.size()-1;i++){
res+=min(left[i],right[i])-height[i];
}
return res;
}
};
方法二:利用单调栈
若前后两个水平一致,弹出当前水平位置一样的坐标位置,可以利用坐标差来计算。
```cpp
class Solution {
public:
int trap(vector<int>& height) {
stack<int> st;
int res=0;
for(int i=0;i<height.size();i++){
while(!st.empty()&&height[i]>height[st.top()]){//遇见凹地方,可以存放水量
int cur=st.top();
st.pop();
if(st.empty()){//没有左边界
break;
}
res+=(min(height[i],height[st.top()])-height[cur])*(i-st.top()-1);//左右最小值乘以宽
}
st.push(i);
}
return res;
}
};
542. 01 矩阵
class Solution {
int dx[4]={0,-1,0,1};
int dy[4]={-1,0,1,0};
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
int n=matrix.size();
int m=matrix[0].size();
vector<vector<int>> vec(n,vector<int>(m,INT_MAX));
queue<pair<int,int>> que;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(matrix[i][j]==0){
que.push({i,j});
vec[i][j]=0;
}
}
}
while(!que.empty()){
auto it=que.front();
que.pop();
for(int i=0;i<4;i++){
int x=it.first+dx[i];
int y=it.second+dy[i];
if(x>=0&&x<n&&y>=0&&y<m&&vec[x][y]!=0){
if(vec[x][y]>vec[it.first][it.second]+1){
vec[x][y]=vec[it.first][it.second]+1;
que.push({x,y});
}
}
}
}
return vec;
}
};
#480. 保龄球
题目描述
打保龄球是用一个滚球去打击十个站立的柱,将柱击倒。一局分十轮,每轮可滚球一次或多次,以击倒的柱数为依据计分。一局得分为十轮得分之和,而每轮的得分不仅与本轮滚球情况有关,还可能与后续一两轮的滚球情况有关。即某轮某次滚球击倒的柱数不仅要计入本轮得分,还可能会计入前一两轮得分。具体的滚球击柱规则和计分方法如下:
(1)若某一轮的第一次滚球就击倒全部十个柱,则本轮不再滚球(若是第十轮则还需另加两次滚球,不妨称其为第十一轮和第十二轮,并不是所有的情况都需要滚第十一轮和第十二轮球)。该轮得分为本次击倒柱数 10 与以后两次滚球所击倒柱数之和。
(2)若某一轮的第一次滚球未击倒十个柱,则可对剩下未倒的柱再滚球一次。如果这两次滚球击倒全部十个柱,则本轮不再滚球(若是第十轮则还需另加一次滚球),该轮得分为这两次共击倒柱数 10 与以后一次滚球所击倒柱数之和。
(3)若某一轮两次滚球未击倒全部十个柱,则本轮不再继续滚球,该轮得分为这两次滚球击倒的柱数之和。
总之,若—轮中一次滚球或两次滚球击倒十个柱,则本轮得分是本轮首次滚球开始的连续三次滚球击倒柱数之和(其中有一次或两次不是本轮滚球)。若一轮内二次滚球击倒柱数不足十个,则本轮得分即为这两次击倒柱数之和。
下面以实例说明如下(字符“/”表示击倒当前球道上的全部的柱):
轮 1 2 3 4 5 6 7 8 9 10 11 12
击球情况 / / / 72 9/ 81 8/ / 9/ / 8/
各轮得分 30 27 19 9 18 9 20 20 20 20
累计总分 30 57 76 85 103 112 132 152 172 192
现在请你编写一个保龄球实时计分程序,用来计算和显示结束后的得分情况。
输入
仅有一行,为前若干轮滚球的情况,每轮滚球用一到两个字符表示,每一个字符表示一次击球,字符“/”表示击倒当前球道上的全部的柱,否则用一个数字字符表示本次滚球击倒的当前球道上的柱的数目,两轮滚球之间用一个空格字符隔开。
如上例对应的输入文件内容为:/ / / 72 9/ 81 8/ / 9/ / 8/
输出
输出一个整数表示最后的得分。
样例输入
/ / / 72 9/ 81 8/ / 9/ / 8/
样例输出
192
#include<iostream>
using namespace std;
#include<string>
struct node {
char num[3];
int num1, num2, flag;//一个字符串有两局,需要两个变量记录当前得分。
};
node s[15];
int main() {
int ans = 0;
int i = 0;
while (cin >>s[i].num) {
if (s[i].num[0] == '/') {
s[i].num1 = s[i].num2 = 10;//num1供上一局进行选择
s[i].flag = 2;//表示直接清空
}
else if (s[i].num[1] == '/') {
s[i].num1 = s[i].num[0] - '0';//间接清空第一局得分
s[i].num2 = 10;//间接清空第二局得分
s[i].flag = 1;//表示间接清空
}
else {
s[i].num1 = s[i].num[0] - '0';
s[i].num2 = s[i].num[1] - '0' + s[i].num1;
}
i++;
}
for (int i = 0; i < 10; i++) {
ans += s[i].num2;//先加上当前局得分
if (s[i].flag == 1) {
ans += s[i + 1].num1;
}
else if (s[i].flag == 2) {
if (s[i + 1].flag == 2) {
ans += 10 + s[i + 2].num1;
}
else {
ans += s[i + 1].num2;
}
}
}
cout << ans << endl;
}
3. 无重复字符的最长子串
分析:求得是最长连续字符串
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char,int> mp;
int res=0;
int left=0;//当前窗口左边值
for(int i=0;i<s.size();i++){
if(mp.find(s[i])==mp.end()||left>mp[s[i]]){
res=max(res,i-left+1);
}
else{
left=mp[s[i]]+1;//更新左窗口值
}
mp[s[i]]=i;
}
return res;
}
};
1695. 删除子数组的最大得分
给你一个正整数数组 nums ,请你从中删除一个含有 若干不同元素 的子数组。删除子数组的 得分 就是子数组各元素之 和 。
返回 只删除一个 子数组可获得的 最大得分 。
如果数组 b 是数组 a 的一个连续子序列,即如果它等于 a[l],a[l+1],…,a[r] ,那么它就是 a 的一个子数组。
示例 1:
输入:nums = [4,2,4,5,6]
输出:17
解释:最优子数组是 [2,4,5,6]
示例 2:
输入:nums = [5,2,1,2,5,2,1,2,5]
输出:8
解释:最优子数组是 [5,2,1] 或 [1,2,5]
分析:是按和来求最长连续数组
class Solution {
public:
int maximumUniqueSubarray(vector<int>& nums) {
vector<int> dp(nums.size());
dp[0]=nums[0];
for(int i=1;i<nums.size();i++){
dp[i]=dp[i-1]+nums[i];//统计连续和数组
}
int res=0;
int left=0;
unordered_map<int,int> mp;
for(int i=0;i<nums.size();i++){
if(mp.find(nums[i])==mp.end()||left>mp[nums[i]]){
if(left==0){
res=dp[i];
}
else{
res=max(res,dp[i]-dp[left-1]);
}
}
else{
left=mp[nums[i]]+1;
}
mp[nums[i]]=i;}
return res;
}
};
#484. 柱状统计图
题目描述
给出一些字符串,总长度不超过 1000,统计其中大写字母的个数,并按照给定样例格式输出。
输入
一堆字符串,每两个字符串之间可能用空格、换行隔开。
输出
参照样例输出柱状统计图,每个 ∗ 表示出现一次,注意每行不要有多余的空格。
样例输入
ABC ABC.DEF()G GCC XY
354342aaaCaa aaaaaaaabcdbcd
样例输出
*
*
*
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
#include<iostream>
using namespace std;
#include<algorithm>
int nums[130];
char str[1005];
int main() {
while (cin >> str) {
for (int i = 0; str[i]; i++) {
nums[str[i]]++;
}
}
int mmax = 0;
//获取最大值
for (int i = 'A'; i < 'Z'; i++) {
mmax = max(mmax, nums[i]);
}
//从上向下遍历
for (int i = mmax; i >0; i--) {
int index = 'A';
//从后往前遍历
for (int j = 'Z'; j > 'A'; j--) {
if (nums[j] >= i) {
index = j;//最远出现距离
break;
}
}
for (int j = 'A'; j <= index; j++) {
if (j != 'A') {
cout << " ";
}
if (nums[j] >= i) {
cout << "*";
}
else {
cout << " ";
}
}
cout << endl;
}
for (char i = 'A'; i <= 'Z'; i++) {
if (i != 'A') {
cout << " ";
}
cout << i;
}
cout << endl;
}