leetcode
leetcode 2701 ~ 2750
将单词恢复初始状态所需的最短时间 I

将单词恢复初始状态所需的最短时间 I

难度:

标签:

题目描述

You are given a 0-indexed string word and an integer k.

At every second, you must perform the following operations:

  • Remove the first k characters of word.
  • Add any k characters to the end of word.

Note that you do not necessarily need to add the same characters that you removed. However, you must perform both operations at every second.

Return the minimum time greater than zero required for word to revert to its initial state.

 

Example 1:

Input: word = "abacaba", k = 3
Output: 2
Explanation: At the 1st second, we remove characters "aba" from the prefix of word, and add characters "bac" to the end of word. Thus, word becomes equal to "cababac".
At the 2nd second, we remove characters "cab" from the prefix of word, and add "aba" to the end of word. Thus, word becomes equal to "abacaba" and reverts to its initial state.
It can be shown that 2 seconds is the minimum time greater than zero required for word to revert to its initial state.

Example 2:

Input: word = "abacaba", k = 4
Output: 1
Explanation: At the 1st second, we remove characters "abac" from the prefix of word, and add characters "caba" to the end of word. Thus, word becomes equal to "abacaba" and reverts to its initial state.
It can be shown that 1 second is the minimum time greater than zero required for word to revert to its initial state.

Example 3:

Input: word = "abcbabcd", k = 2
Output: 4
Explanation: At every second, we will remove the first 2 characters of word, and add the same characters to the end of word.
After 4 seconds, word becomes equal to "abcbabcd" and reverts to its initial state.
It can be shown that 4 seconds is the minimum time greater than zero required for word to revert to its initial state.

 

Constraints:

  • 1 <= word.length <= 50
  • 1 <= k <= word.length
  • word consists only of lowercase English letters.

代码结果

运行时间: 15 ms, 内存: 16.2 MB


// Java Stream Solution
// 思路:利用流操作进行字符串转换和比较。

import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class SolutionStream {
    public int shortestTimeToRestore(String word, int k) {
        int n = word.length();
        return IntStream.rangeClosed(1, n)
                .filter(t -> IntStream.range(0, n)
                        .mapToObj(i -> word.charAt((i + k * t) % n))
                        .collect(Collectors.joining())
                        .equals(word))
                .findFirst()
                .orElse(-1);
    }
}

解释

方法:

本题解通过判断字符串的旋转周期来解决问题。首先计算将整个字符串翻转一遍所需要的最少次数,即 n / k 上取整。然后,从 k 位置开始,以 k 为步长,检查 word 的后缀是否与 word 的前缀相匹配。如果在某个点 i 处,word[i:](即从 i 开始到末尾的子串)与 word[:n-i](即从开头到 n-i 位置的子串)相同,这说明找到了一个周期,word 可以在 i // k 次操作后恢复到初始状态。如果没有找到这样的周期,返回 n / k 的上取整结果。

时间复杂度:

O(n^2 / k)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在每次操作后选择在字符串末尾添加与移除的字符数量相同的任意字符,并不要求与移除的字符相同?
此问题似乎与题解中描述的算法不完全相关,因为算法没有涉及到字符的添加与移除,而是基于字符串旋转和周期性检查的逻辑。可能是对题目描述的误解。题目可能指的是在某些操作中允许某种形式的重组以探测字符串的周期性,但具体细节需要根据题目的完整描述来确认。
🦆
算法中使用的`math.ceil(n / k)`是基于什么考虑?为什么不是`n % k == 0`时直接使用`n / k`?
使用`math.ceil(n / k)`是为了确保在所有字符都能至少被覆盖一次的情况下计算最少的操作次数。即使当`n % k ≠ 0`时,也就是说`k`不能整除`n`,最后一个操作可能只处理剩余的少于`k`的字符,但依然需要计算为一个完整的操作次数。因此,使用向上取整确保所有字符至少被处理一次,而不是只处理到`n - n % k`的位置。
🦆
在算法中,是如何确定从`k`位置开始,以`k`为步长进行检查的?这种方法是否可能遗漏某些周期性的匹配可能?
从`k`位置开始,以`k`为步长进行检查是基于题目设定的操作方式,即每次操作可以考虑长度为`k`的字符串段。此方法的设计是为了有效地检查在每`k`个字符形成的周期中是否可以通过重复达到初始状态。如果`k`是字符串长度的一个因子,则这种方法不会遗漏周期性匹配;但如果`k`不是因子,则可能需要更复杂的方法来检查非`k`步长的周期性,因此在某些情况下可能会遗漏周期性的匹配。

相关问题