Swift 数据结构与算法( ) + Leetcode 掘金 #日新计划更文活动
题目
思路
给定一种规律 pattern 和一个字符串 s ,判断 s 是否遵循相同的规律。
这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 s ****中的每个非空单词之间存在着双向连接的对应规律。
示例1:
输入: pattern = "abba", s = "dog cat cat dog"
输出: true
示例 2:
输入: pattern = "abba", s = "dog cat cat fish"
输出: false
示例 3:
输入: pattern = "aaaa", s = "dog cat cat dog"
输出: false
提示:
1 <= pattern.length <= 300pattern只包含小写英文字母1 <= s.length <= 3000s只包含小写英文字母和' 's不包含 任何前导或尾随对空格s中每个单词都被 单个空格 分隔
解题思路🙋🏻 ♀️
-
问题分析:我们要判断
pattern和s是否有相同的规律。也就是说,pattern中的每个字母应与s中的单词一一对应。同时,这种对应关系应该是唯一的。例如,pattern中的 "a" 对应s中的 "dog",那么 "a" 不能再对应其他的单词。 -
解题思路:我们可以使用两个字典来存储这种对应关系,一个存储
pattern到s的映射,另一个存储s到pattern的映射。
边界思考🤔
代码
class Solution {
func wordPattern(_ pattern: String, _ s: String) -> Bool {
// 将 pattern 转换为字符数组,方便后续按索引访问
let patters = Array(pattern)
// 将字符串 s 按空格分割,然后转换为字符串数组
let words = s.split(separator: " ").map{ String($0) }
// 检查 pattern 的长度和 words 的长度是否一致
if pattern.count != words.count { return false }
// 创建两个字典,用于存储 pattern 到 word 和 word 到 pattern 的映射
var patternDict = [Character:String]()
var wordsDict = [String:Character]()
// 遍历 pattern 的每个字符和对应的 word
for item in 0..<patters.count {
// 当前要比较的 pattern 字符和 word
var patterString = patters[item]
var wordString = words[item]
// 检查 pattern 字符是否已经有对应的 word
if let newPatter = patternDict[patterString] {
// 如果有,但与当前的 word 不匹配,则返回 false
if newPatter != wordString {
return false
}
} else {
// 如果没有,将当前的 pattern 字符和 word 存入字典
patternDict[patterString] = wordString
}
// 同样的,检查 word 是否已经有对应的 pattern 字符
if let newWord = wordsDict[wordString] {
// 如果有,但与当前的 pattern 字符不匹配,则返回 false
if newWord != patterString {
return false
}
} else {
// 如果没有,将当前的 word 和 pattern 字符存入字典
wordsDict[wordString] = patterString
}
}
// 如果所有的 pattern 字符和 word 都匹配,则返回 true
return true
}
}
时空复杂度分析
时间复杂度: )O(n) - 这是因为我们只进行了一次循环,遍历了整个pattern和s字符串。
空间复杂度: O(n) - 我们用了两个字典来存储映射关系,最坏的情况是所有的字符和单词都是不同的,所以空间复杂度是线性的。
错误与反思
let words = s.split(separator: " ").map{ String($0) }
代码的作用是将字符串 s 根据空格进行分割,然后将分割得到的每个子字符串转换成 String 类型,最终得到一个 String 类型的数组。
分解一下这句代码:
s.split(separator: " "):使用空格作为分隔符,将字符串s分割成多个子字符串。这个方法返回的是一个Substring类型的数组。map{ String($0) }:使用map函数对上一步得到的Substring数组进行遍历,将每个Substring转换成String类型。
所以,这句代码的结果是一个 String 类型的数组。
例如,如果 s = "dog cat cat dog",那么 words 的结果就是 ["dog", "cat", "cat", "dog"]。
概念
使用场景与应用
1. 学习的关键概念
- 双向映射: 为了确保一一对应的关系,我们不仅要确保从
pattern到s的映射是唯一的,还要确保从s到pattern的映射也是唯一的。 - 字典的使用: 使用字典来存储和检查映射关系是非常有效的。
2. 实际应用场景
场景1: URL 路由
在Web开发中,URL到函数的映射经常被用来进行路由。例如,"/home"可能映射到homePage()函数。这里就需要确保URL到函数的映射是一一对应的。
技术点: 使用字典来存储URL到函数的映射关系,并在新的映射添加时进行检查。
场景2: 变量替换
在模板渲染或编程中,有时需要将变量名替换为其实际值。这里也需要确保变量名到值的映射是一一对应的。
技术点: 使用字典来存储变量名和其对应的值,并确保不会有重复的映射。
3. iOS app 开发的实际使用场景
场景1: Storyboard ID 到 ViewController 的映射
在iOS开发中,Storyboard ID经常被用来在代码中实例化ViewController。这里需要确保每个Storyboard ID都映射到一个唯一的ViewController。
技术点: 在添加新的ViewController时,检查Storyboard ID是否已经被使用。
场景2: 事件到处理函数的映射
在app中,可能有很多按钮或其他UI元素,当它们被触发时,需要调用一个函数来处理这个事件。这里需要确保每个事件都映射到一个唯一的处理函数。
技术点: 使用字典或其他数据结构来存储事件到处理函数的映射,并确保映射的唯一性。