【LeetCode中等】1419.数青蛙

给你一个字符串 croakOfFrogs,它表示不同青蛙发出的蛙鸣声(字符串 “croak” )的组合。由于同一时间可以有多只青蛙呱呱作响,所以 croakOfFrogs 中会混合多个 “croak” 。

请你返回模拟字符串中所有蛙鸣所需不同青蛙的最少数目。

要想发出蛙鸣 “croak”,青蛙必须 依序 输出 ‘c’, ’r’, ’o’, ’a’, ’k’ 这 5 个字母。如果没有输出全部五个字母,那么它就不会发出声音。如果字符串 croakOfFrogs 不是由若干有效的 “croak” 字符混合而成,请返回 -1 。

示例 1:

输入:croakOfFrogs = “croakcroak”
输出:1
解释:一只青蛙 “呱呱” 两次
示例 2:

输入:croakOfFrogs = “crcoakroak”
输出:2
解释:最少需要两只青蛙,“呱呱” 声用黑体标注
第一只青蛙 “crcoakroak”
第二只青蛙 “crcoakroak”
示例 3:

输入:croakOfFrogs = “croakcrook”
输出:-1
解释:给出的字符串不是 “croak” 的有效组合。

提示:

1 <= croakOfFrogs.length <= 105
字符串中的字符只有 ‘c’, ‘r’, ‘o’, ‘a’ 或者 ‘k’

这道题本身不带多少的算法,个人感觉主要还是读题与模拟的考察,从题干可以知道,青蛙一次都会用croak这五个字母来叫,也就是说青蛙叫这个事不是原子的,一只青蛙叫的过程实际要进行五个音节,这个过程是可以被打断的,需要考虑字符串的连续性。其次,题干只提到了叫完五个字母才算叫完,这句话隐藏的含义是说,叫声一定是进行完的,也就是输入的字符串的长度一定是5的倍数。题目问的是至少要几只青蛙才能完成给出的叫声,一开始错误思路想成了统计所有的croak的数量,但一只青蛙可以叫完了之后继续叫,所以这道题实际上要求的,是同一时刻最多有多少只青蛙发出了c但是还没有叫完,或者说有多少只青蛙在保持叫的这个状态。

所以这道题思路就是遍历字符串,用一个数组记录每只青蛙叫的情况,如果青蛙叫到了c被别的青蛙插队了,就先进行保存,之后叫到r的时候,再接上。一只青蛙只要叫出来了c就算开始了叫,所以只要出现了c,我们就需要进行统计量的加一,相应地,如果有一只青蛙叫到了k完成了叫,统计量就可以减一,最后取统计量的最大值作为结果即可。

#include<bits/stdc++.h>
using namespace std;
int minNumberOfFrogs(string croakOfFrogs){
	if(croakOfFrogs.size()%5!=0)
		return -1;
	int m[5] = {0};
    map<char, int> mp = {{'c', 0}, {'r', 1}, {'o', 2}, {'a', 3}, {'k', 4}};
	int ans = 0;
	int cnt = 0;
	for(int i=0; i<croakOfFrogs.size(); i++){
        int t = mp[croakOfFrogs[i]];

		if(t == 0){
			m[t]++;
			cnt++;
			if(cnt>ans)
				ans = cnt;
		}	
		else{
			if(m[t-1]==0)
				return -1;
			else{
				m[t-1]--;
				if(t==4)
					cnt--;
				else
					m[t]++;
			}
			
		}
		
	}
	if(ans>0)
		return -1;
	else
		return ans;
}
int main()
{
	string s = "crocakcroraoakk";
	cout<<minNumberOfFrogs(s)<<endl;
	return 0;
 } 

在这里插入图片描述
上述代码提交之后时间和空间上都还有很大的优化空间。从时间复杂度上来看,字符串必须要遍历一遍,这是必不可少的时间,在此基础上,进行字母和数字下标的转换(map)以及处理过程是主要的时间开销,要想时间上做改进,可以把map优化掉,直接换switch-case,不仅省时间而且还能抠搜一点开辟map的空间。

int minNumberOfFrogs(string croakOfFrogs){
	if(croakOfFrogs.size()%5!=0)
		return -1;
	int m[5] = {0};
    map<char, int> mp = {{'c', 0}, {'r', 1}, {'o', 2}, {'a', 3}, {'k', 4}};
	int ans = 0;
	int cnt = 0;
	for(int i=0; i<croakOfFrogs.size(); i++){
        int t = mp[croakOfFrogs[i]];

		if(t == 0){
			m[t]++;
			cnt++;
			if(cnt>ans)
				ans = cnt;
		}	
		else{
			if(m[t-1]==0)
				return -1;
				m[t-1]--;
				if(t==4)
					cnt--;
				else
					m[t]++;		
		}
	}
	if(cnt>0)
		return -1;
	else
		return ans;
}

在这里插入图片描述
此外,查看题解前几名才发现,叫声如果合法,字符串的第一个字母必须是c,字符串的最后一个字母必须是k,利用这个条件可以减少很多的时间。

int minNumberOfFrogs(string croakOfFrogs){
	if(croakOfFrogs.size()%5!=0)
		return -1;
	if (croakOfFrogs[0]!='c'||croakOfFrogs[croakOfFrogs.length() - 1]!='k') 
		return -1;

	int m[5] = {0};
	int ans = 0;
	int cnt = 0;
	for(int i=0; i<croakOfFrogs.size(); i++){
		int id;
		switch (croakOfFrogs[i]){
			case 'c':
				id = 0;
				break;
			case 'r':
				id = 1;
				break;
			case 'o':
				id = 2;
				break;
			case 'a':
				id = 3;
				break;
			case 'k':
				id = 4;
				break;
		} 
		
		if(id == 0){
			m[id]++;
			cnt++;
			if(cnt>ans)
				ans = cnt;
		}	
		else{
			if(m[id-1]==0)
				return -1;
			else{
				m[id-1]--;
				if(id==4)
					cnt--;
				else
					m[id]++;
			}
			
		}
		
	}
	if(cnt>0)
		return -1;
	else
		return ans;
}

在这里插入图片描述
考虑到提交的时间和内存情况都有浮动,代码里面能优化的部分已经几乎没有了,所以这道题基本也就这样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ayakanoinu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值