Swift 数据结构与算法( ) + Leetcode 掘金 #日新计划更文活动
题目
给定一个非空的字符串 s
,检查是否可以通过由它的一个子串重复多次构成。
示例 1:
输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。
示例 2:
输入: s = "aba"
输出: false
示例 3:
输入: s = "abcabcabcabc"
输出: true
解释: 可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)
解题思路🙋🏻 ♀️
考虑一个子串 "ab"。如果字符串 ( s ) 由 "ab" 重复构造,那么 ( s ) 可能是 "abab"、"ababab" 等。
现在,让我们图形化地表示这个过程:
- 如果 ( s = \text{"abab"} )(由 "ab" 重复构造)
s: | ab | ab |
当我们将 ( s ) 与自身连接起来得到 ( s' ):
s': | ab | ab | ab | ab |
在 ( s' ) 中,我们可以看到 "ab" 重复了四次。这是因为原始的 ( s ) 已经有了两个 "ab",并且我们再次添加了两个。
- 如果 ( s = \text{"ababab"} )(由 "ab" 重复构造)
s: | ab | ab | ab |
再次,当我们将 ( s ) 与自身连接起来得到 ( s' ):
s': | ab | ab | ab | ab | ab | ab |
在 ( s' ) 中,我们可以看到 "ab" 重复了六次。
这种重复的模式是关键。由于 ( s ) 已经是由 "ab" 重复构造的,所以当我们将 ( s ) 与自身连接时,我们得到了更多的重复。这意味着,无论我们如何从 ( s' ) 中“切开”或删除字符,我们总是能够找到原始的 ( s ),因为它在 ( s' ) 中多次重复。
这就是为什么当我们从 ( s' ) 中删除第一个和最后一个字符时,尽管我们“破坏”了两个 "ab",但原始的 ( s ) 仍然存在于新的字符串中。因为 ( s' ) 有多个重复的 ( s ),所以即使我们删除一部分,其他的仍然存在。
!
边界思考🤔
让我们重新考虑这个问题。现在,我会尝试证明当 �s 不是由重复的子串构成时,经过我们的操作,newS’newS’ 是不可能完整地包含 �s 的。
首先,考虑 �′s′ 的构造。因为 �′s′ 是两个 �s 的拼接,所以它看起来像这样:
�′=�⏟第一份�⏟第二份s′=第一份s第二份s
当我们从 �′s′ 中删除首尾字符时,我们实际上是删除了第一份的第一个字符和第二份的最后一个字符。因此,为了使 newS’newS’ 包含 �s,原始的 �s 必须能够跨越这两个删除的字符。
但这是不可能的,因为 �s 不是由重复的子串构成的。也就是说,除非 �s 是由重复的子串构成的,否则我们不能跨越这两个删除的字符。
因此,我现在可以得出结论,即当 �s 不是由重复的子串构成时,经过我们的操作,newS’newS’ 是不可能完整地包含 �s 的。
代码
func repeatedSubstringPattern(_ s: String) -> Bool {
let newS = s + s
let newsS = newS.dropFirst().dropLast()
return newsS.contains(s)
}
时空复杂度分析
时间复杂度:O(n)
- 创建
newS
:O(n),其中 n 是字符串s
的长度。 dropFirst
和dropLast
操作:这两个操作都是 O(1)。contains
方法:最坏情况下,contains
方法的时间复杂度为 O(n)。
总的时间复杂度为 O(n)。
空间复杂度:O(n)
- 我们创建了一个新的字符串
newS
,其长度是原始字符串s
的两倍。
错误与反思
概念
使用场景与应用
需要学习的概念和实际应用:
需要学习的概念:这一题教我们如何利用字符串的重复性质和简单的字符串操作来判断一个字符串是否可以由其子串重复多次构成。
实际应用:
- 文本匹配:在文本编辑器、搜索引擎和数据库查询中,我们经常需要找到字符串的子串。这一题的核心技术可以为此类问题提供启示。
- 数据压缩:如果我们可以识别出重复的子串,我们可能可以使用这些子串进行数据压缩。
- 密码学:在密码学中,找到重复的模式可能意味着某种加密模式的使用,从而帮助我们解密信息。
3. iOS app 开发的实际应用:
- 搜索功能:在 iOS app 中,例如阅读器或笔记应用,用户可能希望搜索特定的文本或短语。我们可以使用这一题的技术来帮助实现高效的搜索算法。
- 数据同步:在多设备同步应用中(例如 iCloud),我们可能希望识别并压缩重复的数据,从而节省带宽和加快同步速度。
- 动画字符串效果:在某些应用中,我们可能希望为字符串添加动画效果,例如重复出现的字符或子串的动画。这种效果可以通过识别重复的子串来实现。
- 安全验证:在需要用户设置密码的应用中,我们可以检查密码是否包含重复的模式(例如 "123123" 或 "abcabc"),并建议用户选择更安全的密码。