Swift 数据结构与算法(47) + Leetcode290. 单词规律(字符串)

130 阅读3分钟

Swift 数据结构与算法( ) + Leetcode 掘金 #日新计划更文活动

题目

290. 单词规律

思路 给定一种规律 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 <= 300
  • pattern 只包含小写英文字母
  • 1 <= s.length <= 3000
  • s 只包含小写英文字母和 ' '
  • s 不包含 任何前导或尾随对空格
  • s 中每个单词都被 单个空格 分隔

解题思路🙋🏻‍ ♀️

  1. 问题分析:我们要判断 patterns 是否有相同的规律。也就是说,pattern 中的每个字母应与 s 中的单词一一对应。同时,这种对应关系应该是唯一的。例如,pattern 中的 "a" 对应 s 中的 "dog",那么 "a" 不能再对应其他的单词。

  2. 解题思路:我们可以使用两个字典来存储这种对应关系,一个存储 patterns 的映射,另一个存储 spattern 的映射。

边界思考🤔

代码

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) - 这是因为我们只进行了一次循环,遍历了整个patterns字符串。

空间复杂度: O(n) - 我们用了两个字典来存储映射关系,最坏的情况是所有的字符和单词都是不同的,所以空间复杂度是线性的。

错误与反思

let words = s.split(separator: " ").map{ String($0) }

代码的作用是将字符串 s 根据空格进行分割,然后将分割得到的每个子字符串转换成 String 类型,最终得到一个 String 类型的数组。

分解一下这句代码:

  1. s.split(separator: " "):使用空格作为分隔符,将字符串 s 分割成多个子字符串。这个方法返回的是一个 Substring 类型的数组。
  2. map{ String($0) }:使用 map 函数对上一步得到的 Substring 数组进行遍历,将每个 Substring 转换成 String 类型。

所以,这句代码的结果是一个 String 类型的数组。

例如,如果 s = "dog cat cat dog",那么 words 的结果就是 ["dog", "cat", "cat", "dog"]

概念

使用场景与应用

1. 学习的关键概念

  • 双向映射: 为了确保一一对应的关系,我们不仅要确保从patterns的映射是唯一的,还要确保从spattern的映射也是唯一的。
  • 字典的使用: 使用字典来存储和检查映射关系是非常有效的。

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元素,当它们被触发时,需要调用一个函数来处理这个事件。这里需要确保每个事件都映射到一个唯一的处理函数。

技术点: 使用字典或其他数据结构来存储事件到处理函数的映射,并确保映射的唯一性。