2022-02-05每日刷题打卡
飞书——每日一题
316. 去除重复字母
给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
注意:该题与 1081 https://leetcode-cn.com/problems/smallest-subsequence-of-distinct-characters 相同
示例 1:
输入:s = “bcabc”
输出:“abc”
示例 2:
输入:s = “cbacdcbc”
输出:“acdb”
提示:
1 <= s.length <= 104
s 由小写英文字母组成
准备一个哈希表mymap,记录各个字母的出现次数;准备一个字符串res;准备一个数组v,大小开26用来记录已经插入res的字母(初始化都是0,当有一个字母插入res时,把对应位置的数值变成1,至于为什么后面会说)。
先遍历一遍s,把s的各个字母的出现次数记录下来。然后再遍历一遍字符串s,如果v[s[i]-‘a’]==0(即这个字母还没有被插入res中,那就开一个循环,判断res的尾部字符是否大于s[i],而且res的尾部字符是否还有多余的,即mymap[res.back()]>0(因为我们要做的是删除重复的,如果这个字母已经用完了,那我们把这个字母删掉的话这个字母就没了,所以要判断是否这个字母还有多余的,如果没有就不删)。如果满足以上条件,就把res的尾部字符删掉,并且再数值v中把对应的位置的值变成0。当res为空,或者res尾部字符小于s[i]时,停止删除,把s[i]接到res后面。同时在哈希表中把对应的字符的出现次数减一。
class Solution {
public:
string removeDuplicateLetters(string s) {
unordered_map<char,int>mymap;
vector<int>v(26,0);
string res;
int n=s.size();
for(auto i:s)
mymap[i]++;
for(int i=0;i<n;i++)
{
if(v[s[i]-'a']==0)
{
while(res.size()>0&&res.back()>s[i]&&mymap[res.back()]>0)
{
v[res.back()-'a']=0;
res.pop_back();
}
v[s[i]-'a']=1;
res+=s[i];
}
mymap[s[i]]--;
}
return res;
}
};
力扣——每日一题
1219. 黄金矿工
你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格 grid 进行了标注。每个单元格中的整数就表示这一单元格中的黄金数量;如果该单元格是空的,那么就是 0。
为了使收益最大化,矿工需要按以下规则来开采黄金:
每当矿工进入一个单元,就会收集该单元格中的所有黄金。
矿工每次可以从当前位置向上下左右四个方向走。
每个单元格只能被开采(进入)一次。
不得开采(进入)黄金数目为 0 的单元格。
矿工可以从网格中 任意一个 有黄金的单元格出发或者是停止。
示例 1:
输入:grid = [[0,6,0],[5,8,7],[0,9,0]]
输出:24
解释:
[[0,6,0],
[5,8,7],
[0,9,0]]
一种收集最多黄金的路线是:9 -> 8 -> 7。
递归+回溯。遍历grid,当遍历到的格子不为0时,就以那个点为起点开始dfs,每次往上下左右四个方向搜,搜的过程中计算最大值。最后把最大值返回。
class Solution {
public:
int n,m;
int max_ans=0;
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
int getMaximumGold(vector<vector<int>>& grid) {
n=grid.size(),m=grid[0].size();
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(grid[i][j]!=0)
{
bfs(i,j,grid,grid[i][j]);
}
}
}
return max_ans;
}
void bfs(int x,int y,vector<vector<int>> grid,int ans)
{
max_ans=max(max_ans,ans);
grid[x][y]=0;
for(int i=0;i<4;i++)
{
int a=x+dx[i],b=y+dy[i];
if(a>=0&&a<n&&b>=0&&b<m&&grid[a][b]!=0)
{
bfs(a,b,grid,ans+grid[a][b]);
}
}
}
};
AcWing——每日一题
1750. 救生员 - AcWing题库
农夫约翰为他的牛开设了一个游泳池,他认为这将帮助它们放松并产出更多的奶。
为了确保安全,他雇佣了 N 头奶牛作为救生员,每头奶牛的工作班次都是一段连续的时间。
为了简单起见,游泳池每天的开放时间从时刻 0 到时刻 1000。
每个奶牛的工作班次都可以用两个整数来描述,它们分别表示该奶牛工作班次的开始时刻和结束时刻。
例如,从时刻 t=4 开始工作并在时刻 t=7 结束工作的救生员,它的工作时间为三个时间单位(请注意,时间“段”两端的端点是时间轴上的“点”)。
不幸的是,由于资金紧张问题,约翰不得不解雇一头奶牛。
请问通过合理裁员,剩余救生员的工作班次仍然可以覆盖的最大时间有多长?
一个时间间隔内如果存在至少一名救生员当值,那么这个时间间隔就认为是被覆盖的。
输入格式
第一行包含整数 N。
接下来 N 行,每行描述一个救生员的工作班次,包含两个整数,表示一个救生员的开始工作时刻和结束工作时刻。
所有时刻各不相同,不同救生员的工作班次可能有覆盖。
输出格式
输出一个整数,表示解雇掉一头奶牛后,剩余救生员的工作班次仍然可以覆盖的最长时间。
数据范围
1≤N≤100
0≤开始时刻≤结束时刻≤1000
输入样例:
3
5 9
1 4
3 7
输出样例:
7
这题的数据太少,只有1000,所以我们直接用暴力解法。我们枚举一下,每次删除一个区间,再把剩余区间合并,求出每次删掉某个区间后所能覆盖的最大值,并在次过程中维护最大值。最后输出最大的那个覆盖面积。
#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<int,int>PII;
const int N=110;
PII que[N];
int main()
{
int n,res=0;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>que[i].first>>que[i].second;
}
sort(que,que+n);
for(int i=0;i<n;i++)
{
int sum=0,st=-1,ed=-1;
for(int j=0;j<n;j++)
{
if(i!=j)
{
if(que[j].first<=ed)ed=max(ed,que[j].second);
else
{
sum+=ed-st;
st=que[j].first,ed=que[j].second;
}
}
}
sum+=ed-st;
res=max(sum,res);
}
cout<<res<<endl;
return 0;
}
1762. 牛的洗牌 - AcWing题库
农夫约翰坚信快乐的奶牛会产出更多的牛奶,因此他在谷仓中安装了一个巨大的迪斯科球,并计划教他的奶牛跳舞!
在查阅了一些牛的流行舞蹈后,约翰决定教他的奶牛“洗牌舞”。
洗牌舞是由他的 N 只奶牛按一定顺序排成一行,然后连续执行三次“洗牌”,每次“洗牌”都可能会使奶牛重新排序。
为了让奶牛们更容易找到自己所处的位置,约翰用数字 1∼N 对一行中奶牛所在的位置进行了标记,一行中第一头奶牛处于位置 1,第二头奶牛处于位置 2,以此类推,直到位置 N。
每次“洗牌”用 N 个数字 a1,a2,…,aN 来描述,处于位置 i 的奶牛在一次“洗牌”过后,需要移动至位置 ai(因此,每个 ai 在 1…N 范围内)。
幸运的是,所有 ai 都是互不相同的,因此,不会存在多头奶牛在洗牌结束后移动到同一个位置的情况。
约翰的每头奶牛都有一个属于自己的唯一 7 位整数 ID (不含前导 0)。
给定你三轮“洗牌”过后的奶牛排列顺序,请你求出奶牛们的初始排列顺序。
输入格式
第一行包含整数 N。
第二行包含 N 个整数,表示 a1,a2,…,aN。
第三行包含了 N 头奶牛三轮“洗牌”过后的排列顺序,每头奶牛都用其 ID 指代。
输出格式
共 N 行,按照 N 头奶牛的初始排列顺序,每行输出一头奶牛的 ID。
数据范围
1≤N≤100
1≤ai≤N
输入样例:
5
1 3 4 5 2
1234567 2222222 3333333 4444444 5555555
输出样例:
1234567
5555555
2222222
3333333
4444444
就像题目所说的,每次进行洗牌时,会把第i个奶牛移动到第ai个位置上(ai就是第二行的输入数据),比如说原本顺序是1 2 3 4 5,进行第一次洗牌:第一个奶牛移动到第一个位置上,第二个奶牛移动到第3个位置上,第三个奶牛移动到第四个位置上,第四个奶牛移动到第五个位置上,第五个奶牛移动到第2个位置上,这样,就变成了:1 5 2 3 4。这题的第三行输入给了我们奶牛经过三次洗牌得到的顺序,那么我们只要根据移动规则ai逆推三次,就可以得到初始的顺序了。我们把刚刚得到的1 5 2 3 4逆推:第一个奶牛移动到第一个位置上,第三个奶牛移动到第二个位置上,第四个奶牛移动到第3个位置上,第五个奶牛移动到第2个位置上(即把前面的交换次序反过来),就得到了:12 3 4 5。所以我们根据排列后的奶牛id和洗牌规则ai逆推三次,再把逆推后的id以此输出即可。
#include<iostream>
using namespace std;
const int N=110;
int id[N],arr1[N],arr2[N],arr3[N];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>arr1[i];
}
for(int i=1;i<=n;i++)
{
cin>>id[i];
}
for(int i=1;i<=n;i++)
{
arr2[i]=arr1[arr1[i]];
}
for(int i=1;i<=n;i++)
{
arr3[i]=arr2[arr1[i]];
}
for(int i=1;i<=n;i++)
{
cout<<id[arr3[i]]<<endl;
}
return 0;
}