算法(二十一)
题目链接:1419. 数青蛙 - 力扣(LeetCode)
给你一个字符串 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'
算法思路:
模拟⻘蛙的叫声。
当遇到 'r' 'o' 'a' 'k' 这四个字符的时候,我们要去看看每⼀个字符对应的前驱字符,
有没有⻘蛙叫出来。如果有⻘蛙叫出来,那就让这个⻘蛙接下来喊出来这个字符;如果没有,直接返回 -1 ,
当遇到 'c' 这个字符的时候,我们去看看 'k' 这个字符有没有⻘蛙叫出来。如果有,就让
这个⻘蛙继续去喊 'c' 这个字符;如果没有的话,就重新搞⼀个⻘蛙。
class Solution {
public int minNumberOfFrogs(String croakOfFrogs) {
//把其转换为字符数组
char[] croak=croakOfFrogs.toCharArray();
String t="croak";
int n=t.length();
int[] hash=new int[n];
//构建一个hash表存放字符串的下标
Map<Character,Integer> index=new HashMap<Character,Integer>();
for(int i=0;i<n;i++){
index.put(t.charAt(i),i);
}
//先看c字符
for(char ch:croak){
if(ch==t.charAt(0)){
if(hash[n-1]!=0){
hash[n-1]--;
}
hash[0]++;
}else{
int i=index.get(ch);
if(hash[i-1]==0) {
return -1;
}
hash[i-1]--;
hash[i]++;
}
}
for(int i=0;i<n-1;i++){
if(hash[i]!=0){
return -1;
}
}
return hash[n-1];
}
}
题目链接:75. 颜色分类 - 力扣(LeetCode)
给定一个包含红色、白色和蓝色、共 n
个元素的数组 nums
,原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0
、 1
和 2
分别表示红色、白色和蓝色。
必须在不使用库内置的 sort 函数的情况下解决这个问题。
示例 1:
输入:nums = [2,0,2,1,1,0] 输出:[0,0,1,1,2,2]
示例 2:
输入:nums = [2,0,1] 输出:[0,1,2]
提示:
n == nums.length
1 <= n <= 300
nums[i]
为0
、1
或2
在 cur 往后扫描的过程中,保证:
[0, left] 内的元素都是 0 ;
[left + 1, cur - 1] 内的元素都是 1 ;
[cur, right - 1] 内的元素是待定元素;
[right, n] 内的元素都是 2 。
算法流程:
a. 初始化 cur = 0,left = -1, right = numsSize ;
b. 当 cur < right 的时候(因为 right 表⽰的是 2 序列的左边界,因此当 cur 碰到right 的时候,说明已经将所有数据扫描完毕了),⼀直进⾏下⾯循环:
根据 nums[cur] 的值,可以分为下⾯三种情况:
i. nums[cur] == 0 ;说明此时这个位置的元素需要在 left + 1 的位置上,因此交换 left + 1 与 cur 位置的元素,并且让 left++ (指向 0 序列的右边界),cur++ (为什么可以 ++ 呢,是因为 left + 1 位置要么是 0 ,要么是 cur ,交换完毕之后,这个位置的值已经符合我们的要求,因此 cur++ );
ii. nums[cur] == 1 ;说明这个位置应该在 left 和 cur 之间,此时⽆需交换,直接让 cur++ ,判断下⼀个元素即可;
iii. nums[cur] == 2 ;说明这个位置的元素应该在 right - 1 的位置,因此交换right - 1 与 cur 位置的元素,并且让 right-- (指向 2 序列的左边界), cur 不变(因为交换过来的数是没有被判断过的,因此需要在下轮循环中判断)
c. 当循环结束之后:
[0, left] 表⽰ 0 序列;
[left + 1, right - 1] 表⽰ 1 序列;
[right, numsSize - 1] 表⽰ 2 序列。
class Solution {
public void swap(int[] nums,int i,int j){
int tmp=nums[i];
nums[i]=nums[j];
nums[j]=tmp;
}
public void sortColors(int[] nums) {
int left=-1,right=nums.length,i=0;
while(i<right){
if(nums[i]==0){
swap(nums,++left,i++);
}else if(nums[i]==1){
i++;
}else{
swap(nums,--right,i);
}
}
}
}