leetcode每日一题系列-学生出勤记录I-「java原生函数」-学生出勤记录II-「动态规划」

636 阅读4分钟

这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战

leetcode-551-学生出勤记录

[博客链接]

菜🐔的学习之路

掘金首页

[题目描述]

给你一个字符串 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'

Related Topics

  • 字符串
  • 👍 81 👎 0

[题目链接]

leetcode题目链接

[github地址]

代码链接

[思路介绍]

思路一:java原生函数

  • 条件判断即可
 public boolean checkRecord(String s) {
     return !(s.indexOf("A") != s.lastIndexOf("A") || s.contains("LLL"))
 }
  • 时间复杂度O(nn)
  • 空间复杂度O(1)

思路延伸

  • 预测一下明天的每日一题 「题目描述」 可以用字符串表示一个学生的出勤记录,其中的每个字符用来标记当天的出勤情况(缺勤、迟到、到场)。记录中只含下面三种字符:

  • '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 <= 105

Related Topics

  • 动态规划
  • 👍 144 👎 0
  • 这预感是明天的每日一题
  • easy直接到hard也是狠,先写一个常规的dp分析
  • 正常递归思路是每一个元素三选一dfs(i)
  • 基线条件i达到n||当前排列不满足题目要求的时候时退出递归
  • 时间复杂度O(3n)O(3^n)可以很容易的发现必然tle
  • 但是由此可以推出dp方程dp[i]
  • 表示由 i个元素排列组合满足题目要求的方案数量
  • 初始化dp[0] = 0;
  • dp[n]第递推思路可以从如下角度分析
    • 选取第n个元素的原则是需要使选取之后的排列满足要求
    • 也就是分如下几种情况
      • 当前序方案dp[n-1]有A的时候,只可以添加P、L(需要下一个条件判定)
      • 当前序方案dp[n-1]末尾是"LL"的时候,只可以添加P
      • 其余情况可添加所有元素A、L、P
    • 由此可以发现我们需要记录每种方案数的两个指标
      • 1、A的数量
      • 2、末尾两位的字符串
    • 因此一维的dp[n]暂时来看无法满足定义
  • 需要定义三维dp[i][j][k] 表示使用i个元素包含j个A,且长度末尾为k个l的方案数量
    • 初始化
      • dp[1][0][1] = 1
      • dp[1][1][0] = 1
      • dp[1][0][0] = 1
    • 递推方程
      • dp[i][0][0] = (dp[i-1][0][0] + dp[i-1][0][1] + dp[i-1][0][2]) % mod;
      • dp[i][1][0] = (dp[i-1][1][0] + dp[i-1][1][1] + dp[i-1][1][2]) % mod;
      • dp[i][0][1] = (dp[i-1][0][0]) % mod;
      • dp[i][0][2] = (dp[i-1][0][1]) % mod;
      • dp[i][1][1] = (dp[i-1][1][0]) % mod;
      • dp[i][1][2] = (dp[i-1][1][1]) % mod;
      • dp[i][1][0] += (dp[i - 1][0][0] + dp[i - 1][0][1] + dp[i - 1][0][2]) % mod
public int checkRecord(int n) {
    long[][][] dp = new long[n + 1][2][3];
    dp[1][0][1] = 1;
    dp[1][1][0] = 1;
    dp[1][0][0] = 1;
    int mod = (int) 1e9 + 7;
    for (int i = 2; i <= n; i++) {
        dp[i][0][0] = (dp[i - 1][0][0] + dp[i - 1][0][1] + dp[i - 1][0][2]) % mod;
        dp[i][1][0] = (dp[i - 1][1][0] + dp[i - 1][1][1] + dp[i - 1][1][2]) % mod;
        dp[i][0][1] = dp[i - 1][0][0];
        dp[i][0][2] = dp[i - 1][0][1];
        dp[i][1][1] = dp[i - 1][1][0];
        dp[i][1][2] = dp[i - 1][1][1];
        dp[i][1][0] += (dp[i - 1][0][0] + dp[i - 1][0][1] + dp[i - 1][0][2]) % mod;
    }
    return (int)((dp[n][0][0] + dp[n][0][1] + dp[n][0][2] + dp[n][1][0] + dp[n][1][1] + dp[n][1][2]) % mod);
}
  • 时间复杂度O(n)
  • 空间复杂度O(n)