LeetCode 551. 学生出勤记录 I /552. 学生出勤记录 II(动态规划)/345. 反转字符串中的元音字母(set加入元素的方法)

Posted Zephyr丶J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 551. 学生出勤记录 I /552. 学生出勤记录 II(动态规划)/345. 反转字符串中的元音字母(set加入元素的方法)相关的知识,希望对你有一定的参考价值。

551. 学生出勤记录 I

2021.8.17 每日一题

题目描述

给你一个字符串 s 表示一个学生的出勤记录,其中的每个字符用来标记当天的出勤情况(缺勤、迟到、到场)。记录中只含下面三种字符:

‘A’:Absent,缺勤
‘L’:Late,迟到
‘P’:Present,到场
如果学生能够 同时 满足下面两个条件,则可以获得出勤奖励:

按 总出勤 计,学生缺勤(‘A’)严格 少于两天。
学生 不会 存在 连续 3 天或 3 天以上的迟到(‘L’)记录。
如果学生可以获得出勤奖励,返回 true ;否则,返回 false 。

示例 1:

输入:s = “PPALLP”
输出:true
解释:学生缺勤次数少于 2 次,且不存在 3 天或以上的连续迟到记录。

示例 2:

输入:s = “PPALLL”
输出:false
解释:学生最后三天连续迟到,所以不满足出勤奖励的条件。

提示:

1 <= s.length <= 1000
s[i] 为 ‘A’、‘L’ 或 ‘P’

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/student-attendance-record-i
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

class Solution {
    public boolean checkRecord(String s) {
        int l = s.length();
        int countA = 0;
        for(int i = 0; i < l; i++){
            if(s.charAt(i) == 'A')
                countA++;
            if(countA >= 2)
                return false;
            int countL = 0;
            int t = i;
            while(t < l && s.charAt(t) == 'L'){
                t++;
                countL++;
                if(countL == 3)
                    return false;
            }
            if(t > i)
                i = t - 1;
        }
        return true;
    }
}

要学会用API

class Solution {
    public boolean checkRecord(String s) {
        return !s.contains("LLL") && !(s.indexOf('A') < s.lastIndexOf('A')); 
    }
}

552. 学生出勤记录 II

2021.8.18 每日一题

题目描述

可以用字符串表示一个学生的出勤记录,其中的每个字符用来标记当天的出勤情况(缺勤、迟到、到场)。记录中只含下面三种字符:
‘A’:Absent,缺勤
‘L’:Late,迟到
‘P’:Present,到场
如果学生能够 同时 满足下面两个条件,则可以获得出勤奖励:

按 总出勤 计,学生缺勤(‘A’)严格 少于两天。
学生 不会 存在 连续 3 天或 3 天以上的迟到(‘L’)记录。
给你一个整数 n ,表示出勤记录的长度(次数)。请你返回记录长度为 n 时,可能获得出勤奖励的记录情况 数量 。答案可能很大,所以返回对 109 + 7 取余 的结果。

示例 1:

输入:n = 2
输出:8
解释:
有 8 种长度为 2 的记录将被视为可奖励:
“PP” , “AP”, “PA”, “LP”, “PL”, “AL”, “LA”, “LL”
只有"AA"不会被视为可奖励,因为缺勤次数为 2 次(需要少于 2 次)。

示例 2:

输入:n = 1
输出:3

示例 3:

输入:n = 10101
输出:183236316

提示:

1 <= n <= 10^5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/student-attendance-record-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

动态规划:
刚开始我是这样定义状态方程的:

dp[i][0]表示之前没有A,当前为A的时候,获得出勤奖励的情况数量,如果能从这个状态转移,就说明有A了
dp[i][1]表示当前为L的时候,获得出勤奖励的情况数量
dp[i][2]表示当前为两个连续的L的时候,获得出勤奖励的情况数量
dp[i][3]表示当前为P的时候,获得出勤奖励的情况数量

然后发现有没有A没办法搞,所以想是不是要在每个状态又定义一个维度表示当前是否有A,即

dp[i][0][0]表示当前为P的时候,并且没有A,获得出勤奖励的情况数量
dp[i][0][1]表示当前为P的时候,并且有A,获得出勤奖励的情况数量
dp[i][1][0]表示当前为L的时候,并且没有A的情况下,获得出勤奖励的情况数量
dp[i][1][1]表示当前为L的时候,并且有一个A的情况下,获得出勤奖励的情况数量
dp[i][2][0]表示当前为两个连续的L的时候,没有A,获得出勤奖励的情况数量
dp[i][2][1]表示当前为两个连续的L的时候,有A,获得出勤奖励的情况数量

发现还是不太对,因为那如果当前是A的话,当前为P的情况该怎么转移呢,所以应该定义成有没有L

dp[i][0][0]表示当前连续L的个数为0的时候,并且没有A,获得出勤奖励的情况数量
dp[i][0][1]表示当前连续L的个数为0的时候,并且有A,获得出勤奖励的情况数量
dp[i][1][0]表示当前为L的时候,并且没有A的情况下,获得出勤奖励的情况数量
dp[i][1][1]表示当前为L的时候,并且有一个A的情况下,获得出勤奖励的情况数量
dp[i][2][0]表示当前为两个连续的L的时候,没有A,获得出勤奖励的情况数量
dp[i][2][1]表示当前为两个连续的L的时候,有A,获得出勤奖励的情况数量

class Solution {
    public int checkRecord(int n) {
        //动规,三个状态
        //dp[i][0]表示之前没有A,当前为A的时候,获得出勤奖励的情况数量,如果能从这个状态转移,就说明有A了
        //dp[i][1]表示当前为L的时候,获得出勤奖励的情况数量
        //dp[i][2]表示当前为两个连续的L的时候,获得出勤奖励的情况数量
        //dp[i][3]表示当前为P的时候,获得出勤奖励的情况数量
        //dp[i][0]表示之前没有A,当前为A的时候,获得出勤奖励的情况数量,如果能从这个状态转移,就说明有A了
        //不行

        //dp[i][0][0]表示当前连续L个数为0的时候,并且没有A,获得出勤奖励的情况数量
        //dp[i][0][1]表示当前连续L个数为0的时候,并且有A,获得出勤奖励的情况数量
        //dp[i][1][0]表示当前为L的时候,并且没有A的情况下,获得出勤奖励的情况数量
        //dp[i][1][1]表示当前为L的时候,并且有一个A的情况下,获得出勤奖励的情况数量
        //dp[i][2][0]表示当前为两个连续的L的时候,没有A,获得出勤奖励的情况数量
        //dp[i][2][1]表示当前为两个连续的L的时候,有A,获得出勤奖励的情况数量

        int MOD = (int)1e9 + 7;
        int[][][] dp = new int[n + 1][3][2];
        //初始化,表示第一个位置,可以放任何一个字母
        
        dp[1][0][0] = 1;    //第一个为P
        dp[1][0][1] = 1;    //第一个为A
        dp[1][1][0] = 1;    //第一个为L
        dp[1][1][1] = 0;    
        
        //dp[0][0][0] = 1;

        //状态转移
        for(int i = 2; i <= n; i++){
            //如果当前为P,可以从其他任何A数量相同的状态转移
            for(int j = 0; j < 3; j++){
                for(int k = 0; k < 2; k++){
                    dp[i][0][k] = (dp[i][0][k] + dp[i - 1][j][k]) % MOD;
                }
            }

            //如果当前为L,那么状态就是之前一天L少一个的状态
            for(int j = 1; j < 3; j++){
                for(int k = 0; k < 2; k++){
                    dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j - 1][k]) % MOD;
                }
            }
             
            //如果当前为A,那么就是由之前没有A的状态
            for(int j = 0; j < 3; j++){
                dp[i][0][1] = (dp[i][0][1] + dp[i - 1][j][0]) % MOD;
            }
        }
        int res = 0;
        for(int j = 0; j < 3; j++){
            for(int k = 0; k < 2; k++){
                res = (res + dp[n][j][k]) % MOD;
            }
        }
        return res;
    }
}

矩阵快速幂就不写了,赶时间哈哈

345. 反转字符串中的元音字母

2021.8.19 每日一题

题目描述

编写一个函数,以字符串作为输入,反转该字符串中的元音字母。

示例 1:

输入:“hello”
输出:“holle”

示例 2:

输入:“leetcode”
输出:“leotcede”

提示:

元音字母不包含字母 “y” 。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-vowels-of-a-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

幸亏我还记得原因字母是啥。。
双指针反转,中间写那段有点快排的感觉了

class Solution {
    public String reverseVowels(String s) {
        //元音字母,我记得是aeiou,如果还有大写,也加进去
        //然后我其实没看懂它这个反转是啥意思,意思是左右翻转呗
        int l = s.length();
        char[] cc = s.toCharArray();
        int left = 0;
        int right = l - 1;
        Set<Character> set = new HashSet<>();
        set.add('a');
        set.add('e');
        set.add('i');
        set.add('o');
        set.add('u');
        set.add('A');
        set.add('E');
        set.add('I');
        set.add('O');
        set.add('U');
        while(left < right){
            while(left < right && !set.contains(cc[left])){
                left++;
            }
            while(left < right && !set.contains(cc[right])){
                right--;
            }
            char c = cc[left];
            cc[left] = cc[right];
            cc[right] = c;
            left++;
            right--;
        }
        return new String(cc);
    }
}

我这里哈希写的好烦,看下官解,就是优雅

	public boolean isVowel(char ch) {
        return "aeiouAEIOU".indexOf(ch) >= 0;
    }

再找几个:
用列表建哈希,秒

	private final static HashSet<Character> vowel = new HashSet<>(
        Arrays.asList('a','e','i','o','u','A','E','I','O','U')
    );

直接创建哈希时添加

	Set<Character> vowels = new HashSet<>(){{
        add('a');
        add('e'); 
        add('i'); 
        add('o'); 
        add('u'); 
        add('A'); 
        add('E'); 
        add('I'); 
        add('O'); 
        add('U');
    }}; 

switch

	private boolean isVowel(char c) {
        switch(c) {
            case 'a' :
            case 'e' :
            case 'i' :
            case 'o' :
            case 'u' :
            case 'A' :
            case 'E' :
            case 'I' :
            case 'O' :
            case 'U' :
                return false;
        }
        return true;
    }

三叶姐好秀:
直接创建静态的变量,在所有测试用例的时候这个变量就仅仅被创建一次
注意:这里用数组模拟哈希减的是空字符 ’ ’

	static boolean[] hash = new boolean[128];
    static char[] vowels = new char[]{'a','e','i','o','u'};
    static {
        for (char c : vowels) {
            hash[c - ' '] = hash[Character.toUpperCase(c) - ' '] = true;
        }
    }
static char[] vowels = new char[]{'a','e','i','o','u'};
    static Set<Character> set = new HashSet<>();
    static {
        for (char c : vowels) {
            set.add(c);
            set.add(Character.toUpperCase(c));
        }
    }

以上是关于LeetCode 551. 学生出勤记录 I /552. 学生出勤记录 II(动态规划)/345. 反转字符串中的元音字母(set加入元素的方法)的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode刷题551-简单-学生出勤记录 I

Leetcode刷题100天—551.学生出勤记录I(字符串)—day12

LeetCode 551 学生出勤记录I[选择 字符串] HERODING的LeetCode之路

LeetCode:学生的出勤记录|551

LeetCode 551. Student Attendance Record I (学生出勤纪录 I)

leetcode刷题总结551-600