2022-01-16每日刷题打卡
一本通
1252:走迷宫
【题目描述】
一个迷宫由R行C列格子组成,有的格子里有障碍物,不能走;有的格子是空地,可以走。
给定一个迷宫,求从左上角走到右下角最少需要走多少步(数据保证一定能走到)。只能在水平方向或垂直方向走,不能斜着走。
【输入】
第一行是两个整数,R和C,代表迷宫的长和宽。( 1<= R,C <= 40)
接下来是R行,每行C个字符,代表整个迷宫。
空地格子用‘.’表示,有障碍物的格子用‘#’表示。
迷宫左上角和右下角都是‘.’。
【输出】
输出从左上角走到右下角至少要经过多少步(即至少要经过多少个空地格子)。计算步数要包括起点和终点。
【输入样例】
5 5
..###
#....
#.#.#
#.#.#
#.#..`
【输出样例】
9
#include<iostream>
using namespace std;
#include<string.h>
typedef pair<int, int> PII;
const int N = 50;
char g[N][N];
int h[N][N];
int n, m;
PII que[N * N];
int bfs()
{
int dx[] = { 0,1,0,-1 }, dy[] = { 1,0,-1,0 };
int hh = 0, tt = 0;
memset(h, -1, sizeof h);
h[0][0] = 1;
que[0] = { 0,0 };
while (hh <= tt)
{
auto t = que[hh++];
for (int i = 0; i < 4; i++)
{
int x = t.first + dx[i], y = t.second + dy[i];
if (x >= 0 && x < n && y >= 0 && y < m && h[x][y] == -1 && g[x][y] == '.')
{
h[x][y] = h[t.first][t.second] + 1;
que[++tt] = { x,y };
}
}
}
return h[n - 1][m - 1];
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> g[i][j];
cout << bfs() << endl;
return 0;
}
1254:走出迷宫
【题目描述】
当你站在一个迷宫里的时候,往往会被错综复杂的道路弄得失去方向感,如果你能得到迷宫地图,事情就会变得非常简单。
假设你已经得到了一个n×mn×m的迷宫的图纸,请你找出从起点到出口的最短路。
【输入】
第一行是两个整数nn和mm(1≤n,m≤1001≤n,m≤100),表示迷宫的行数和列数。
接下来nn行,每行一个长为mm的字符串,表示整个迷宫的布局。字符‘.
’表示空地,‘#
’表示墙,‘S
’表示起点,‘T
’表示出口。
【输出】
输出从起点到出口最少需要走的步数。
【输入样例】
3 3
S#T
.#.
...
【输出样例】
6
#include<iostream>
using namespace std;
#include<string.h>
typedef pair<int, int>PII;
const int N = 1010;
char g[N][N];
int h[N][N];
PII que[N*N];
int n, m, a, b,c,d;
int bfs()
{
memset(h, -1, sizeof h);
h[c][d] = 0;
int hh = 0, tt = 0;
int dx[4] = { 0,1,0,-1 }, dy[4] = { 1,0,-1,0 };
que[0] = { c,d };
while (hh <= tt)
{
auto t = que[hh++];
for (int i = 0; i < 4; i++)
{
int x = dx[i] + t.first, y = dy[i] + t.second;
if (x >= 0 && x < n && y >= 0 && y < m && h[x][y] == -1 && (g[x][y] == '.'|| g[x][y] == 'T'))
{
h[x][y] = h[t.first][t.second] + 1;
que[++tt] = { x,y };
}
}
}
return h[a][b];
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
{
cin >> g[i][j];
if (g[i][j] == 'T')
a = i, b = j;
else if (g[i][j] == 'S')
c = i, d = j;
}
cout<<bfs();
return 0;
}
蓝桥杯——历届真题
等差数列【第十届】【省赛】【B组】
问题描述
数学老师给小明出了一道等差数列求和的题目。但是粗心的小明忘记了一部分的数列,只记得其中 N 个整数。
现在给出这 N 个整数,小明想知道包含这 N 个整数的最短的等差数列有几项?
输入格式
输入的第一行包含一个整数 N。
第二行包含 N 个整数 A₁, A₂, · · · , AN。(注意 A₁ ∼ AN 并不一定是按等差数列中的顺序给出)
输出格式
输出一个整数表示答案。
样例输入
5
2 6 4 10 20
样例输出
10
样例说明
包含 2、6、4、10、20 的最短的等差数列是 2、4、6、8、10、12、14、16、 18、20。
对数组排序,然后算出每个数之间的差值,算出各个差值的最大公因数,再通过最小值和最大值利用等差数列公式就可以求出最少可以有几项了。
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
int gcd(int a, int b)//辗转相除法 在两个数中求得最大公约数,当一方为0时,返回另一方。
{
return b ? gcd(b, a % b) : a;
}
int main()
{
int n;
cin >> n ;
vector<int>v(n);
for (int i = 0; i < n; i++)
cin >> v[i];
sort(v.begin(), v.end());
int d = 0;
for (int i = 1; i < n; i++)d = gcd(d, v[i] - v[0]);
if (d)cout << (v[n - 1] - v[0]) / d + 1;
else cout << n;
return 0;
}
力扣
5980. 将字符串拆分为若干长度为 k 的组
字符串 s 可以按下述步骤划分为若干长度为 k 的组:
第一组由字符串中的前 k 个字符组成,第二组由接下来的 k 个字符串组成,依此类推。每个字符都能够成为 某一个 组的一部分。
对于最后一组,如果字符串剩下的字符 不足 k 个,需使用字符 fill 来补全这一组字符。
注意,在去除最后一个组的填充字符 fill(如果存在的话)并按顺序连接所有的组后,所得到的字符串应该是 s 。
给你一个字符串 s ,以及每组的长度 k 和一个用于填充的字符 fill ,按上述步骤处理之后,返回一个字符串数组,该数组表示 s 分组后 每个组的组成情况 。
示例 1:
输入:s = “abcdefghi”, k = 3, fill = “x”
输出:[“abc”,“def”,“ghi”]
解释:
前 3 个字符是 “abc” ,形成第一组。
接下来 3 个字符是 “def” ,形成第二组。
最后 3 个字符是 “ghi” ,形成第三组。
由于所有组都可以由字符串中的字符完全填充,所以不需要使用填充字符。
因此,形成 3 组,分别是 “abc”、“def” 和 “ghi” 。
遍历s,把遍历到的字符存在准备好的字符串str上,当str的长度等于k时,把str存入vector中,并清空str。遍历s结束后,如果str不为空,就用fill加在str后面,使其长度等于k,再把它存入vector中。返回vector。
class Solution {
public:
vector<string> divideString(string s, int k, char fill) {
vector<string>v;
int n=s.size();
string str;
for(int i=0;i<n;i++)
{
str+=s[i];
if(str.size()==k)
{
v.push_back(str);
str.clear();
}
}
if(str.size()!=0)
{
while(str.size()!=k)
{
str+=fill;
}
v.push_back(str);
str.clear();
}
return v;
}
};
5194. 得到目标值的最少行动次数
你正在玩一个整数游戏。从整数 1 开始,期望得到整数 target 。
在一次行动中,你可以做下述两种操作之一:
递增,将当前整数的值加 1(即, x = x + 1)。
加倍,使当前整数的值翻倍(即,x = 2 * x)。
在整个游戏过程中,你可以使用 递增 操作 任意 次数。但是只能使用 加倍 操作 至多 maxDoubles 次。
给你两个整数 target 和 maxDoubles ,返回从 1 开始得到 target 需要的最少行动次数。
示例 1:
输入:target = 5, maxDoubles = 0
输出:4
解释:一直递增 1 直到得到 target 。
贪心的思想,要想次数最少,说明要在尽可能大的情况下使用加倍,但我们不知道什么时候才算大,所以如果从1开始变到target是很麻烦的,但反过来求就很简单了,即target变成1需要几步,如果有翻倍次数,就先把target减半,直到翻倍次数用完为止,有一点,当target为奇数时不能使用翻倍,要先通过–把它变成偶数才行,举个例子,target是15,如果直接减半就是7,但我们知道,7要变成15要先翻倍再+1,所以反过来就应该是先-1后减半。当翻倍次数用完后,我们只能一步步-1来达到目标数,这一步如果还像前面那样一步步-1的话会超时的,这里的数据最高开到1e9,如果一次减半机会都没有,光靠一步步减,减到1需要1e9-1步,必然超时,所以当翻倍次数用完后,就不用傻傻的一步步循环减了,直接把步骤数加上target-1即可,最后返回步骤数。
class Solution {
public:
int minMoves(int target, int maxDoubles) {
int ans=0;
while(target!=1)
{
if(maxDoubles&&target%2==0)
{
ans++;
target/=2;
maxDoubles--;
}
else if(maxDoubles==0)
{
ans+=target-1;
break;
}
else
{
ans++;
target--;
}
}
return ans;
}
};