按键持续时间最长的键

标签: 数组 字符串

难度: Easy

LeetCode 设计了一款新式键盘,正在测试其可用性。测试人员将会点击一系列键(总计 n 个),每次一个。

给你一个长度为 n 的字符串 keysPressed ,其中 keysPressed[i] 表示测试序列中第 i 个被按下的键。releaseTimes 是一个升序排列的列表,其中 releaseTimes[i] 表示松开第 i 个键的时间。字符串和数组的 下标都从 0 开始 。第 0 个键在时间为 0 时被按下,接下来每个键都 恰好 在前一个键松开时被按下。

测试人员想要找出按键 持续时间最长 的键。第 i 次按键的持续时间为 releaseTimes[i] - releaseTimes[i - 1] ,第 0 次按键的持续时间为 releaseTimes[0]

注意,测试期间,同一个键可以在不同时刻被多次按下,而每次的持续时间都可能不同。

请返回单次按键 持续时间最长 的键,如果有多个这样的键,则返回 按字母顺序排列最大 的那个键。

示例 1:

输入:releaseTimes = [9,29,49,50], keysPressed = "cbcd"
输出:"c"
解释:按键顺序和持续时间如下:
按下 'c' ,持续时间 9(时间 0 按下,时间 9 松开)
按下 'b' ,持续时间 29 - 9 = 20(松开上一个键的时间 9 按下,时间 29 松开)
按下 'c' ,持续时间 49 - 29 = 20(松开上一个键的时间 29 按下,时间 49 松开)
按下 'd' ,持续时间 50 - 49 = 1(松开上一个键的时间 49 按下,时间 50 松开)
按键持续时间最长的键是 'b' 和 'c'(第二次按下时),持续时间都是 20
'c' 按字母顺序排列比 'b' 大,所以答案是 'c'

示例 2:

输入:releaseTimes = [12,23,36,46,62], keysPressed = "spuda"
输出:"a"
解释:按键顺序和持续时间如下:
按下 's' ,持续时间 12
按下 'p' ,持续时间 23 - 12 = 11
按下 'u' ,持续时间 36 - 23 = 13
按下 'd' ,持续时间 46 - 36 = 10
按下 'a' ,持续时间 62 - 46 = 16
按键持续时间最长的键是 'a' ,持续时间 16

提示:

  • releaseTimes.length == n
  • keysPressed.length == n
  • 2 <= n <= 1000
  • 1 <= releaseTimes[i] <= 109
  • releaseTimes[i] < releaseTimes[i+1]
  • keysPressed 仅由小写英文字母组成

Submission

运行时间: 24 ms

内存: 16.1 MB

class Solution:
    def slowestKey(self, releaseTimes: List[int], keysPressed: str) -> str:
        max_duration = releaseTimes[0]
        max_key = keysPressed[0]

        for i in range(1, len(releaseTimes)):
            duration = releaseTimes[i] - releaseTimes[i-1]
            if duration > max_duration or (duration == max_duration and keysPressed[i] > max_key):
                max_duration = duration
                max_key = keysPressed[i]

        return max_key

Explain

该题解采用遍历的方式。首先初始化最长持续时间 max_duration 和对应的按键 max_key 为第一个按键的持续时间和按键。然后从第二个按键开始遍历,计算每个按键的持续时间,并与当前的最长持续时间进行比较。如果当前按键的持续时间更长,或者持续时间相同但按键字母顺序更大,则更新 max_duration 和 max_key。最后返回持续时间最长的按键。

时间复杂度: O(n)

空间复杂度: O(1)

class Solution:
    def slowestKey(self, releaseTimes: List[int], keysPressed: str) -> str:
        max_duration = releaseTimes[0]  # 初始化最长持续时间为第一个按键的持续时间
        max_key = keysPressed[0]  # 初始化对应的按键为第一个按键

        for i in range(1, len(releaseTimes)):
            duration = releaseTimes[i] - releaseTimes[i-1]  # 计算当前按键的持续时间
            if duration > max_duration or (duration == max_duration and keysPressed[i] > max_key):
                max_duration = duration  # 更新最长持续时间
                max_key = keysPressed[i]  # 更新对应的按键

        return max_key  # 返回持续时间最长的按键

Explore

如果`releaseTimes`数组包含负数或者不是递增的,该算法可能会出现问题。按照定义,`releaseTimes`应该代表从开始到每个按键被释放的时间点,因此理论上应该是一个递增数组。如果数组不是递增的,那么`releaseTimes[i] - releaseTimes[i-1]`可能会计算出负数或零,这在实际情况中是无意义的,因为一个按键的持续时间不能是负数或零。如果存在这样的数据,需要对输入进行预处理或在实现中增加逻辑来处理这种异常情况。

当`keysPressed`字符串为空或`releaseTimes`数组为空时,原始算法没有处理这种边界情况,这可能会导致数组越界错误或逻辑错误(如初始化的`max_duration`和`max_key`变量无法正确设置)。在实际应用中,应该在函数开始时检查这些数组是否为空,并相应地返回一个错误信息或特定值,例如返回空字符串或抛出一个异常来指示输入数据不合法。

算法从索引1开始遍历`releaseTimes`数组是因为需要计算每个按键的持续时间,即当前按键释放时间与前一个按键释放时间的差。第一个按键的持续时间可以直接假定为`releaseTimes[0]`,因为它是从开始到第一个按键被释放的时间。从索引1开始可以直接使用`releaseTimes[i] - releaseTimes[i-1]`来计算第i个按键的持续时间。

理论上`releaseTimes[i]`和`releaseTimes[i-1]`相等的情况应该不会发生,因为这表示两个连续的按键在同一时间点被释放,这在实际应用中是不合理的。如果发生这种情况,按照当前算法逻辑,`duration`将计算为0,这意味着当前按键的持续时间为0,不会更新`max_duration`和`max_key`。因此,虽然这种情况不应该发生,但如果确实发生了,当前的实现不会对结果产生影响,除非所有的持续时间都为0,这时候只有第一个按键会被考虑。