leetcode Task02 字符串基础知识 125. 验证回文串 344. 反转字符串 28. 实现 strStr() 796. 旋转字符串 208. 实现 Trie (前缀树)


一、字符串基础知识

学习链接
字符串匹配:

  • 单模式串匹配问题(Single Pattern Matching)
  • 多模式串匹配问题(Single Pattern Matching)

二、125. 验证回文串

题目:
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。

说明:本题中,我们将空字符串定义为有效的回文串。

示例:
输入: “A man, a plan, a canal: Panama”
输出: true
解释:“amanaplanacanalpanama” 是回文串

思路1:
将字符串处理一下,去掉空格和标点符号,保留字母和数字。
将处理好的字符串翻转对比一下即可。

class Solution:
    def isPalindrome(self, s: str) -> bool:
        s_r= ""
        for s1 in s:
            if s1.isalnum():
                s_r = s_r + s1.lower()
        return s_r == s_r[::-1]

思路2:
对撞指针。

class Solution:
    def isPalindrome(self, s: str) -> bool:
        left = 0
        right = len(s)-1
        while left < right:
            if not s[left].isalnum():
                left += 1
                continue
            if not s[right].isalnum():
                right -= 1
                continue
            
            if s[left].lower() == s[right].lower():
                right -= 1
                left += 1
            else:
                return False
        return True

三、0344.反转字符串

题目:
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

示例:

思路:
使用双指针,原地转换。

class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        left = 0
        right = len(s)-1
        while left < right:
            temp = s[right]
            s[right] = s[left]
            s[left] = temp
            right -= 1
            left += 1
        

四、单模式串匹配

暴力BF算法:
最坏的时间复杂度为 O ( m ∗ n ) O(m*n) O(mn)
最佳的时间复杂度为 O ( m ) O(m) O(m)

RK(Rabin Karp)算法:
利用滚动哈希的思想,将 O ( m ) O(m) O(m)降为 O ( 1 ) O(1) O(1),从而RK算法的时间复杂度为 O ( n ) O(n) O(n)
但出现哈希冲突时,算法的效率会降低,最差的情况将退化成 O ( m ∗ n ) O(m*n) O(mn)

KMP(Knuth Morris Pratt)算法
通过构造前缀表,当匹配失败时,只回退模式串即可。
复杂度:
构造前缀表的复杂度为 O ( m ) O(m) O(m)
匹配阶段的复杂度为 O ( n ) O(n) O(n)
因此,总的复杂度为 O ( m + n ) O(m+n) O(m+n)

五、0028.实现 strStr()

题目:
实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。

示例:
输入:haystack = “hello”, needle = “ll”
输出:2

思路1:
使用暴力法进行求解,即前面提到的BF算法:

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        if needle == "":
            return 0
        n,m = len(haystack),len(needle)
        i,j = 0,0
        while i<n and j<m:
            if haystack[i] == needle[j]:
                i += 1
                j += 1
            else:
                i = i - j + 1
                j = 0
        
        if j == m:
            return i - j 
        else:
            return -1

思路2:
也可以使用RK算法和KMP算法进行求解。

六、0796.旋转字符串

题目:
给定两个字符串, s 和 goal。如果在若干次旋转操作之后,s 能变成 goal ,那么返回 true 。
s 的 旋转操作 就是将 s 最左边的字符移动到最右边。
例如, 若 s = ‘abcde’,在旋转一次之后结果就是’bcdea’ 。

示例:
输入: s = “abcde”, goal = “cdeab”
输出: true

思:1:
首先,如果原始字符串s和目标字符串goal的长度不等,则任何的旋转都无法使二者相等。
接着,将原始字符串首位拼接,即s+s,就包括了字符串s循环一圈所有的可能性。

class Solution:
    def rotateString(self, s: str, goal: str) -> bool:
        if len(s) != len(goal):
            return False
        if goal in s+s:
            return True
        else:
            return False

这里偷懒,使用了内置的字符串匹配。

思路2:
自己实现了一下kmp算法,效率有点低hhh

class Solution:
    def rotateString(self, s: str, goal: str) -> bool:
        if len(s)!=len(goal):
            return False
        flag = self.kmp(s+s,goal)
        if flag == -1:
            return False
        else:
            return True
    #KMP
    def kmp(self,T:str,p:str) -> int:
        n,m = len(T),len(p)

        next = self.generateNext(p)
        j = 0
        for i in range(n):
            while j>0 and T[i] != p[j]:
                j = next[j-1]
            if T[i] == p[j]:
                j += 1
            if j==m:
                return i-m+1
        return -1



    def generateNext(self,p:str):
        m = len(p)
        next = [0 for _ in range(m)]

        left = 0
        for right in range(1,m):
            while left > 0 and p[left]!=p[right]:
                left = next[left-1]
            if p[left] == p[right]:
                left += 1
            next[right] = left
        
        return next

七、0208. 实现 Trie (前缀树)

题目:
Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。

请你实现 Trie 类:
Trie() 初始化前缀树对象。
void insert(String word) 向前缀树中插入字符串 word 。
boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。

示例:
输入
[“Trie”, “insert”, “search”, “search”, “startsWith”, “insert”, “search”]
[[], [“apple”], [“apple”], [“app”], [“app”], [“app”], [“app”]]
输出
[null, null, true, false, true, null, true]

解释
Trie trie = new Trie();
trie.insert(“apple”);
trie.search(“apple”); // 返回 True
trie.search(“app”); // 返回 False
trie.startsWith(“app”); // 返回 True
trie.insert(“app”);
trie.search(“app”); // 返回 True

思路:
按照字典树的定义,编写代码即可。
参考链接

class Node:
    def __init__(self):
        self.children = dict()
        self.isEnd = False

class Trie:

    def __init__(self):
        self.root = Node()

    def insert(self, word: str) -> None:
        cur = self.root
        for ch in word:
            if ch not in cur.children:
                cur.children[ch] = Node()
            cur = cur.children[ch]
        cur.isEnd = True

    def search(self, word: str) -> bool:
        cur = self.root
        for ch in word:
            if ch not in cur.children:
                return False
            cur = cur.children[ch]
        return cur is not None and cur.isEnd 

    def startsWith(self, prefix: str) -> bool:
        cur = self.root
        for ch in prefix:
            if ch not in cur.children:
                return False
            cur = cur.children[ch]
        return cur is not None

插入操作:直接从根节点开始遍历即可,没找到字符就新建一个Node()

查找操作:直接从根节点开始遍历,找到后要判断是不是在这里有一个isEnd标记。

查找前缀操作:直接从根节点开始遍历,找到后无需判断isEnd标记。

八、211. 添加与搜索单词 - 数据结构设计

题目:
请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。

实现词典类 WordDictionary :

WordDictionary() 初始化词典对象
void addWord(word) 将 word 添加到数据结构中,之后可以对它进行匹配
bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回 false 。word 中可能包含一些 ‘.’ ,每个 . 都可以表示任何一个字母。

示例:
输入:
[“WordDictionary”,“addWord”,“addWord”,“addWord”,“search”,“search”,“search”,“search”]
[[],[“bad”],[“dad”],[“mad”],[“pad”],[“bad”],[“.ad”],[“b…”]]
输出:
[null,null,null,null,false,true,true,true]

解释:
WordDictionary wordDictionary = new WordDictionary();
wordDictionary.addWord(“bad”);
wordDictionary.addWord(“dad”);
wordDictionary.addWord(“mad”);
wordDictionary.search(“pad”); // 返回 False
wordDictionary.search(“bad”); // 返回 True
wordDictionary.search(“.ad”); // 返回 True
wordDictionary.search(“b…”); // 返回 True

class Trie:
    def __init__(self):
        self.children = dict()
        self.isEnd = False

    def insert(self, word: str) -> None:
        cur = self
        for ch in word:
            if ch not in cur.children:
                cur.children[ch] = Trie()
            cur = cur.children[ch]
        cur.isEnd = True

    def search(self, word: str) -> bool:
        cur = self
        for i in range(len(word)):
            ch = word[i]
            if ch == ".":
                for node in cur.children.values():
                    if node.search(word[i+1:]):
                        return True
                return False
            elif ch not in cur.children:
                return False
            cur = cur.children[ch]
        return cur.isEnd

class WordDictionary:

    def __init__(self):
        self.tree = Trie()


    def addWord(self, word: str) -> None:
        self.tree.insert(word)


    def search(self, word: str) -> bool:
        return self.tree.search(word)

这个题超时了…暂时不知道怎么解决。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值