2022-01-19每日刷题打卡
一本通
1256:献给阿尔吉侬的花束
【题目描述】
阿尔吉侬是一只聪明又慵懒的小白鼠,它最擅长的就是走各种各样的迷宫。今天它要挑战一个非常大的迷宫,研究员们为了鼓励阿尔吉侬尽快到达终点,就在终点放了一块阿尔吉侬最喜欢的奶酪。现在研究员们想知道,如果阿尔吉侬足够聪明,它最少需要多少时间就能吃到奶酪。
迷宫用一个R×C的字符矩阵来表示。字符S表示阿尔吉侬所在的位置,字符E表示奶酪所在的位置,字符#表示墙壁,字符.表示可以通行。阿尔吉侬在1个单位时间内可以从当前的位置走到它上下左右四个方向上的任意一个位置,但不能走出地图边界。
【输入】
第一行是一个正整数T(1 ≤ T ≤ 10),表示一共有T组数据。
每一组数据的第一行包含了两个用空格分开的正整数R和C(2 ≤ R, C ≤ 200),表示地图是一个R×C的矩阵。
接下来的R行描述了地图的具体内容,每一行包含了C个字符。字符含义如题目描述中所述。保证有且仅有一个S和E。
【输出】
对于每一组数据,输出阿尔吉侬吃到奶酪的最少单位时间。若阿尔吉侬无法吃到奶酪,则输出“oop!”(只输出引号里面的内容,不输出引号)。每组数据的输出结果占一行。
【输入样例】
3
3 4
.S..
###.
..E.
3 4
.S..
.E..
....
3 4
.S..
####
..E.
【输出样例】
5
1
oop!
走迷宫类型题目,就是起点和终点不固定,我们只要在录入迷宫的时候,记录下来’S’和‘E’字符的位置即可。
#include<iostream>
using namespace std;
#include<vector>
#include<string.h>
#include<algorithm>
typedef pair<int, int>PII;
const int N = 210;
int a, b, c, d, n, m;
char g[N][N];
int h[N][N];
int dx[4] = { 1,0,-1,0 }, dy[4] = { 0,1,0,-1 };
PII que[N * N];
int bfs()
{
if (a == c && b == d)return 0;
memset(h, -1, sizeof h);
que[0] = { a,b };
int hh = 0, tt = 0;
h[a][b] = 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] == '.'||g[x][y]=='E'))
{
h[x][y] = h[t.first][t.second] + 1;
que[++tt] = { x,y };
}
}
}
return h[c][d];
}
int main()
{
int w;
cin >> w;
while (w--)
{
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] == 'S')
{
a = i, b = j;
}
else if (g[i][j] == 'E')
{
c = i, d = j;
}
}
int t = bfs();
if (t == -1)cout << "oop!" << endl;
else cout << t << endl;
}
return 0;
}
1251:仙岛求药
【题目描述】
少年李逍遥的婶婶病了,王小虎介绍他去一趟仙灵岛,向仙女姐姐要仙丹救婶婶。叛逆但孝顺的李逍遥闯进了仙灵岛,克服了千险万难来到岛的中心,发现仙药摆在了迷阵的深处。迷阵由M×N个方格组成,有的方格内有可以瞬秒李逍遥的怪物,而有的方格内则是安全。现在李逍遥想尽快找到仙药,显然他应避开有怪物的方格,并经过最少的方格,而且那里会有神秘人物等待着他。现在要求你来帮助他实现这个目标。
下图 显示了一个迷阵的样例及李逍遥找到仙药的路线。
【输入】
输入有多组测试数据. 每组测试数据以两个非零整数 M 和 N 开始,两者均不大于20。M 表示迷阵行数, N 表示迷阵列数。接下来有 M 行, 每行包含N个字符,不同字符分别代表不同含义:
1)‘@’:少年李逍遥所在的位置;
2)‘.’:可以安全通行的方格;
3)‘#’:有怪物的方格;
4)‘*’:仙药所在位置。
当在一行中读入的是两个零时,表示输入结束。
【输出】
对于每组测试数据,分别输出一行,该行包含李逍遥找到仙药需要穿过的最少的方格数目(计数包括初始位置的方块)。如果他不可能找到仙药, 则输出 -1。
【输入样例】
8 8
.@##...#
#....#.#
#.#.##..
..#.###.
#.#...#.
..###.#.
...#.*..
.#...###
6 5
.*.#.
.#...
..##.
.....
.#...
....@
9 6
.#..#.
.#.*.#
.####.
..#...
..#...
..#...
..#...
#.@.##
.#..#.
0 0
【输出样例】
10
8
-1
上题同款解法,只不过有一点是,while循环的判断条件是cin,这样只要有输入就会一直循环下去,这里当输入0 0时就算程序结束了,我们要加一个判断,当n和m为0 0时,跳出while循环,如果不跳出,会使得多输出一个-1(自己看代码想想为什么),使得答案不正确。
#include<iostream>
using namespace std;
#include<vector>
#include<string.h>
#include<algorithm>
typedef pair<int, int>PII;
const int N = 210;
int a, b, c, d, n, m;
char g[N][N];
int h[N][N];
int dx[4] = { 1,0,-1,0 }, dy[4] = { 0,1,0,-1 };
PII que[N * N];
int bfs()
{
if (a == c && b == d)return 0;
memset(h, -1, sizeof h);
que[0] = { a,b };
int hh = 0, tt = 0;
h[a][b] = 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] == '.'||g[x][y]=='*'))
{
h[x][y] = h[t.first][t.second] + 1;
que[++tt] = { x,y };
}
}
}
return h[c][d];
}
int main()
{
while (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] == '@')
{
a = i, b = j;
}
else if (g[i][j] == '*')
{
c = i, d = j;
}
}
int t = bfs();
cout << t << endl;
}
return 0;
}
力扣——每日一题
219. 存在重复元素 II
给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 i 和 j ,满足 nums[i] == nums[j] 且 abs(i - j) <= k 。如果存在,返回 true ;否则,返回 false 。
示例 1:
输入:nums = [1,2,3,1], k = 3
输出:true
示例 2:
输入:nums = [1,0,1,1], k = 1
输出:true
示例 3:
输入:nums = [1,2,3,1,2,3], k = 2
输出:false
准备一个哈希表,数字为key,数字在nums中的下标为vul,遍历数组nums,每遍历一个元素判断当前元素是否在哈希表中出现过,如果出现过,判断当前元素的下标减去哈希表存的下标是否小于等于k,如果是就返回true,不是就以当前元素的下标换掉哈希表中存的下标。(判断小于等于k的时候不需要用abs(),因为我们遍历数组是一个从小索引到大索引的过程,也就是说,如果哈希表不为空,那么存下来的索引肯定是小于我们当前索引的,因为它比我们早出现,所以才能比我们先进入哈希表。而替换掉的原因是,如果当前元素的下标减去哈希表存下的下标,不满足小于等于k的条件,那当我们遍历之后的元素,肯定也是不符合,也就是说哈希表中存的下标已经“过时“了,我们要”与时俱进“,所以要换掉它。
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
unordered_map<int ,int>mymap;
int n=nums.size();
for(int i=0;i<n;i++)
{
int num=nums[i];
if(mymap.count(num)&&i-mymap[num]<=k)return true;
mymap[num]=i;
}
return false;
}
};
蓝桥杯——算法提高
算法提高 长度统计
问题描述
给出n个线段以及它们的左端点和右端点。我们要求得到这些线段覆盖部分的长度。如线段[1,2]和[2,3]覆盖了数轴上1到3这个部分,所以它们覆盖的长度就是2。
输入格式
第一行一个数n表示有n条线段,之后的n行每行两个整数表示每个线段的左端点和右端点。
输出格式
一个数表示覆盖部分的长度。
样例输入
3
1 2
2 3
4 5
样例输出
3
数据规模和约定
0<n<=1000, 答案不超过32位整数。
自定义排序规则,以每个区间的左端点为基准升序排序。然后遍历所有区间,如果当前区间的右端点大于等于下一个区间的左端点,则说明这两个区间可以合并,比如[1,2] 和[2,4]这两个区间就可以合并成[1,4],这样总的覆盖长度就是3,但要注意,合并区间并不是单纯的当前区间的左端点和下一个区间的右端点,这样是错误的,比如[1,4]和[2,3]区间,如果是用当前区间的左端点和下一个区间的右端点合并,那结果就是[1,3],但我们知道这结果是错误的,应该是[1,4],所以合并区间的规则应该是遍历过的区间中最小的数为左端点,最大数为右端点。最后计算差值并累计起来输出即可。
#include<iostream>
using namespace std;
#include<vector>
#include<string.h>
#include<algorithm>
typedef pair<int, int>PII;
bool cmp(PII a, PII b)
{
return a.first < b.first;
}
int main()
{
int n;
vector<PII>v;
cin >> n;
for (int i = 0; i < n; i++)
{
int a, b;
cin >> a >> b;
vector<int>v1;
v.push_back({ a,b });
}
sort(v.begin(), v.end(), cmp);
int ans = 0;
int i = 0, j = 0, star = v[i].first, end = v[i].second;
while (i < n)
{
if (j + 1 < n && end >= v[j + 1].first)
{
end = max(end, v[j + 1].second);
j++;
}
else
{
ans += end - star;
j++;
if (j >= n)break;
star = v[j].first;
end = v[j].second;
i = j;
}
}
cout << ans << endl;
return 0;
}