2022-02-05每日刷题打卡

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值