C++日常刷题积累
今日刷题汇总 - day019
1、小易的升级之路
1.1、题目
1.2、思路
读完题,知道根据游戏规则输入n和a,表示怪物数量n行和初始能力值a,每一次遍历一个元素b1就判断一次大小,小于或等于能力值就直接累加,否则就累加它们的最大公约数即可。根据要求模拟实现即可,主要是处理输入输出即可。
1.3、程序实现
#include <iostream>
using namespace std;
//最大公约数
int gcd(int a,int b)
{
if(b == 0)
return a;
return gcd(b,a%b);
}
int main()
{
int n,a;
while(cin >> n >>a)
{
int b;
for(int i = 0;i < n;i++)
{
cin >> b;
if(b <= a)
{
a += b;
}
else
{
a += gcd(a,b);
}
}
cout << a << endl;
}
return 0;
}
2、礼物的最大价值
2.1、题目
2.2、思路
读完题,知道在n*m棋盘中,从左上角以一定的规则(每次向右或者向下移动一格),直到到达棋盘的右下角,求最优的路线获取最大价值的礼物。分析示例和题目理解后知道,属于dp动态规划路径问题,采用动态规划就需要确定状态表示和状态转移方程,那么以dp[i][j] 表示到达i,j位置处能获取的最大价值是多少。推导状态转移方程,dp[i][j]位置可以由上方的方格达到,也可以由左方方格达到,所以就分为到达dp[i-1][j]和dp[i][j-1]的位置的价值最大值,加上dp[i][j]自身的价值。即:dp[i][j] = max(dp[i-1][j] , dp[i][j-1]) + 自己的价值即可。那么接下来,就是程序实现。
2.3、程序实现 – 简单dp
首先,根据dp动态规划思路定义dp数组,然后获取矩阵的大小m,n,接着遍历状态转移方程:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + grid[i - 1][j - 1];最后输出dp[m][n]即可。
class Solution {
public:
int dp[210][210] = { 0 };
int maxValue(vector<vector<int> >& grid)
{
int m = grid.size();
int n = grid[0].size();
for(int i = 1; i <=m; i++)
{
for(int j = 1; j <= n; j++)
{
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + grid[i - 1][j - 1];
}
}
return dp[m][n];
}
};
3、对称之美
3.1、题目
3.2、思路
读完题,知道有1到n行个字符串,从每个字符串中串取一个字符组成一个新字符串,并且判断该字符串是否是满足回文字符串,其中注意新字符串的第i个字母只能从第i行的字符串中选出,当时第一遍没注意这句话,想着利用栈处理一下,结果写到后面,耽误很多时间,写都写了贴出来,提醒自己细心。然后,正确的解法应该严格按照题目要求处理,结合哈希和左右指针判断回⽂串。
判断左右指针相等的时候,应该看看两个字符串中有没有相同的字符即可。
3.3、程序实现 – stack(error)
#include <iostream>
#include <stack>
using namespace std;
int main()
{
int t, n;
cin >> t;
while (t--)
{
cin >> n;
int mid = n / 2;
stack<char> st;
char ch;
cin >> ch;
if (n == 1)
{
cout << "Yes" << endl;
continue;
}
st.push(ch);
for (int i = 1; i < n; i++)
{
if (mid == i && n % 2 == 1)
{
cin >> ch;
continue;
}
char temp = st.top();
cin >> ch;
if (temp == ch)
st.pop();
else
st.push(ch);
}
if (st.empty())
cout << "Yes" << endl;
else
cout << "No" << endl;
}
return 0;
}
3.4、程序实现 – 哈希+双指针
那么利用哈希基本思想就是标记出现过的字符,存在vis数组中等待后面遍历两边判断是否都为真,然后结合双指针,由于这里是对字符串操作,并不是上面栈的思维操作字符,所以需要两个指针,遍历分别自己索指向的字符串中是否有相同的字符,所以简单的理解就是分别在大字符中遍历小字符串找前后相同的字符。为了方便理解画个示意图:
除此之外,注意将数组清空,方便下一组正确引用。
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int t, n;
string s;
bool vis[110][26];
bool check(int left, int right)//可以根据题目理解,left和right理解为第几行的字符串
{
for (int i = 0; i < 26; i++)
{
if (vis[left][i] && vis[right][i])//根据思路分析中,遍历两个小字符串中存在两个相同字符,所以均为真则返回真
return true;
}
return false;
}
int main()
{
cin >> t;
while (t--)
{
memset(vis, 0, sizeof vis); // 清空之前的数据
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> s;
for (auto ch : s)
{
vis[i][ch - 'a'] = true;
}
}
int left = 0, right = n - 1;
while (left < right)
{
if (!check(left, right)) //见思路分析图
break;
left++;
right--;
}
if (left < right)
cout << "No" << endl;
else
cout << "Yes" << endl;
}
return 0;
}