zoukankan      html  css  js  c++  java
  • 剑指offer2 字符串

    字符串常和其他数据类型放一起考

    数组

    字符串下标天然是数组

    后进先出,包括括号匹配、路径拆分等字符串题目,注意,python中的栈用list的append和pop实现栈的压入弹出

    哈希表

    主要是用来做快速匹配

    队列

    先进先出

    字符串方法

    • 获取字符串长度: len(str)
    • 判断字符串是否相等: str== str2
    • 获取字符串的子串: str[begin: end:step​]
    • 拆分字符串: str.split(regex,maxsplit)
    • 获取下标: python 只有index()
    • 大小写转换: lower() upper()
    • 返回指定下标的字符:str[i]

    剑指 Offer II 014. 字符串中的变位词

    题目描述

    给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的某个变位词。

    换句话说,第一个字符串的排列之一是第二个字符串的 子串 。

    剑指 Offer II 014. 字符串中的变位词 - 力扣(LeetCode) (leetcode-cn.com)

    题解

    滑动固定大小的窗口,双指针

    用字符统计就可以做,遍历一次s2

    def checkInclusion(self, s1: str, s2: str) -> bool:
        arr1, arr2, lg = [0] * 26, [0] * 26, len(s1)
        if lg > len(s2):
            return False
        # 维护一个arr2, 使它在s2上往右滑直到碰到尾巴
        for i in range(lg):
            arr1[ord(s1[i]) - ord('a')] += 1
            arr2[ord(s2[i]) - ord('a')] += 1
    
        for j in range(lg, len(s2)):
            if arr1 == arr2:
                return True
            arr2[ord(s2[j - lg]) - ord('a')] -= 1
            arr2[ord(s2[j]) - ord('a')] += 1
        return arr1 == arr2

    剑指 Offer II 015. 字符串中的所有变位词

    题目描述

    给定两个字符串 s 和 p,找到 s 中所有 p 的 变位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

    变位词 指字母相同,但排列不同的字符串

    剑指 Offer II 015. 字符串中的所有变位词 - 力扣(LeetCode) (leetcode-cn.com)

    题解

    固定窗口双指针

    上一道题改一下:

    def findAnagrams(self, s: str, p: str) -> List[int]:
        arr1, arr2, lg = [0] * 26, [0] * 26, len(p)
        ret = []
        if lg > len(s):
            return []
        # 维护一个arr2, 使它在s2上往右滑直到碰到尾巴
        for i in range(lg):
            arr1[ord(p[i]) - ord('a')] += 1
            arr2[ord(s[i]) - ord('a')] += 1
    
        for j in range(lg, len(s)+1):
            if arr1 == arr2:
                ret.append(j-lg)
            if j<len(s):
                arr2[ord(s[j - lg]) - ord('a')] -= 1
                arr2[ord(s[j]) - ord('a')] += 1
        return ret

    剑指 Offer II 016. 不含重复字符的最长子字符串

    题目描述

    给定一个字符串 s ,请你找出其中不含有重复字符的 最长连续子字符串 的长度。

    剑指 Offer II 016. 不含重复字符的最长子字符串 - 力扣(LeetCode) (leetcode-cn.com)

    题解

    双指针+hash表

    双指针,维护一个字典,key为字符,value为上一次遇到该字符的位置

    def lengthOfLongestSubstring(self, s: str) -> int:
        # 双指针+hash表
        dic, res, i = {}, 0, -1
        for j in range(len(s)):
            if s[j] in dic:
                i = max(dic[s[j]], i) # 更新左指针 i
            dic[s[j]] = j # 哈希表记录
            res = max(res, j - i) # 更新结果
        return res

    动态规划dp

    动态规划列表 dp ,dp[j] 即 代表以字符 s[j] 为结尾的 “最长不重复子字符串” 的长度。所以只需要一次for循环

    def lengthOfLongestSubstring(self, s: str) -> int:
            #动态规划+hash表 设动态规划列表 dp ,dp[j]    即 代表以字符 s[j] 为结尾的 “最长不重复子字符串” 的长度。但是由于只要max, 只需用一个变量做动态规划额外的空间
            dic = {} #记录s[i] 的 i  s[i] 为距离s[j]最近的那个字符  即s[i]=s[j] i<j
            
            tmp = 0
            res = 0
            for j in range(len(s)):
                i = dic.get(s[j],-1) #获取索引i  参数-1表示找不到就返回-1
                dic[s[j]] = j
                if tmp < j-i:  #tmp中存的是dp[j-1]  即当前(shangyige)字符的dp[值]
                    tmp = tmp+1
                else:
                    tmp = j-i
                res = max(res,tmp)  # max(dp[j-1],dp[j])
            return res

    剑指 Offer II 017. 含有所有字符的最短字符串

    题目描述

    给定两个字符串 s 和 t 。返回 s 中包含 t 的所有字符的最短子字符串。如果 s 中不存在符合条件的子字符串,则返回空字符串 "" 。

    如果 s 中存在多个符合条件的子字符串,返回任意一个。

    注意: 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/M1oyTv

    题解

    暴力搜(当然超出时间限制,但其实还可以)

    def minWindow(self, s: str, t: str) -> str:
        #集合 
        # t中所有字符都要在
        lg,n = len(t),len(s)
        set_t = set(t)
        set_tmp = {}
        ret = n+1
        res = ""
        for end in range(n):
            start = 0
            while start <=end:
                tempset = set(s[start:end+1])
                flag = True
                for _ in set_t:
                    if s[start:end+1].count(_) < t.count(_):
                        flag = False
                if flag and tempset.intersection(set_t) == set_t:
                    if end-start+1<ret:
                        ret = end-start+1
                        res = s[start:end+1]
                start+=1
        return res

    双指针+hash表


    Counter()函数
    Counter()是collections里面的一个类,作用是计算出字符串或者列表等中不同元素出现的个数,返回值可以理解为一个字典,所以对传回来的统计结果的操作都可以当作对字典的操作
    Note: 字符串置函数count(),只能统计字符串中某个元素出现的个数。
    from collections import Counter
    t="xbnpukocakzqzuhdlxoga"
    hashmap = Counter(t)
    print(hashmap)
    
    output:
    Counter({'x': 2, 'u': 2, 'k': 2, 'o': 2, 'a': 2, 'z': 2, 'b': 1, 'n': 1, 'p': 1, 'c': 1, 'q': 1, 'h': 1, 'd': 1, 'l': 1, 'g': 1})

    • 设t有n个字符,则挑出来的子字符串至少应有n个字符
    • 使用hashmap来保存窗口还需要的字符
     
    def minWindow(self, s: str, t: str) -> str:
        # 双指针+hash表
        m, n = len(s), len(t)
        if m < n: return ""
        hashmap = Counter(t)
        count = n #这个变量很关键,保证含有字符串t中的所有字符
        ans = ""
        tmpLen = m + 1
        i, j = 0, 0
        while j < m:
            if s[j] in hashmap:
                if hashmap[s[j]] > 0:
                    count -= 1
                hashmap[s[j]] -= 1
            while count == 0:
                if j - i + 1 < tmpLen:
                    tmpLen = j - i + 1
                    ans = s[i:j+1]
                if s[i] in hashmap:
                    if hashmap[s[i]] >= 0:
                        count += 1
                    hashmap[s[i]] += 1
                #当把左指针向右移动时,要对应更新hashmap和count
                i += 1
            j += 1
        return ans

    剑指 Offer II 018. 有效的回文

    题目描述

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

    本题中,将空字符串定义为有效的 回文串 。

    剑指 Offer II 018. 有效的回文 - 力扣(LeetCode) (leetcode-cn.com)

    题解

    双指针+正则表达式

    • 忽略大小写:转换成大写or小写
    • 只考虑字母和数字:使用正则表达式去除多余字符

    正则表达式re

    Day 9:Python 字符串和正则介绍总结 - PiaYie - 博客园 (cnblogs.com)

    匹配 a-z0-9

    str1="".join(re.findall(r'[a-z0-9]*',s.lower()))

    匹不是中文、大小写、数字的其他字符

    cop = re.compile("[^\u4e00-\u9fa5^a-z^A-Z^0-9]")

    def isPalindrome(self, s: str) -> bool:
        if not s:
            return true
        # 是否回文,
        # 忽略大小写
        str1 = s.lower()
        # 只保留字母+数字
        cop = re.compile("[^\u4e00-\u9fa5^a-z^A-Z^0-9]") # 匹配不是中文、大小写、数字的其他字符
        str1 = cop.sub('', str1)
        i,j = 0,len(str1)-1
        ret = True
        while i<=j:
            if str1[i]!=str1[j]:
                return False
            i+=1
            j-=1
        return ret   

    剑指 Offer II 019. 最多删除一个字符得到回文

    题目描述

    给定一个非空字符串 s,请判断如果 最多 从字符串中删除一个字符能否得到一个回文字符串。

    剑指 Offer II 019. 最多删除一个字符得到回文 - 力扣(LeetCode) (leetcode-cn.com)

    题解

    利用上题判断回文的方法

    暴力搜

    遍历一次数组,copy删除每一个字符后的字符串再做回文check,超出时间限制mmp

    import re
    s ="xinoiqersxmiddtxzemwdklzwforualxmfkgvjzcqgmamrijpvmuyskclmyawsfjcwmgsvumvuklkuozziygyoyodvlhbdxgcwwvkgzgjugtscsawowvbzwutfuipozjjpwennhwxzbaswiqxrqehummyoekvfwsozusaibibfygbkxwtrdmgfhvrgwnniuvkqwneknoxomubaukvpgkjfpftxjfvytngastmzgzsxjrqcutqbnzfnhdypllfhyjntptmudayqgkfzfsitzpvxohndlzwcbyivkkazhlhfatefiaazwxishxusjztkluxkqtunamsbtkryipoaebfshocwrhukpoknqbjmojeutqwivxwmvwshvqkbxryyirpcdxufqruhodtfyobuvpvdubmahbgdudwzjpfoeyieihvfxrlatikzthubzuenjlqcnjdyloimtolntfxhgjpnbahpvaravtfvkhzvkynbmljyqnjydeljtmwmxkqxmnywmzrcrkmqgpykhjeyxybtdyktsymaojbpzyhijdlmhsubsshhacagqzcodfcyvbbfyearfmheahmprcdllgcnblwuutghqoixevurqgpvsaxueqzcsdhxoiigpjzqhjkevnzcnaerpdoqzyclkpidqghoanqaccfudqggloeclppyjidinkdydfutkivxdodorxfgzjaawngeycuhfbctmojuvtmraudilnlvqrjuxugdmwxnocwgmvcyuxegkrwxnmxubiwphjbigcpkolllcghyicsaaccfifyjjaqanqatzqbwbfgqzrmmtgrgupdsnakfolnclcyzfvwtrtyedltlsxdefpvefilecjvnrewmhodnzsgaxpeekgrtgddqowynyhsbcraroacrmcdyqhhichtyyitlfxsfuyiqmvunaraeghkuqtqkztvnrjicfbenqlffdohkcceyllircklrdeclqtdkhllci"
    def validPalindrome( s: str) -> bool:
        def isPalindrome(str1: str) -> bool:
            if not s:
                return True
            i,j = 0,len(str1)-1
            while i<=j:
                if str1[i]!=str1[j]:
                    return False
                i+=1
                j-=1
            return True 
        str1 = s.lower()
            # 只保留字母+数字
        cop = re.compile("[^\u4e00-\u9fa5^a-z^A-Z^0-9]") # 匹配不是中文、大小写、数字的其他字符
        str1 = cop.sub('', str1)
        if isPalindrome(str1):
            return True
        for i in range(len(str1)):
            temp = str1[:i]+str1[i+1:]
            if isPalindrome(temp):
                return True
        return False
    
    print(validPalindrome(s))

    回文性质+技巧

     只要做三次check判断就可以了

    def validPalindrome(self, s):
        # check函数用来确定两个字符是不是相等
        def check(l, r):
            while l <= r:
                if s[l] != s[r]:
                    break
                l += 1
                r -= 1
            return l, r
    
        mid = len(s) // 2
        left, right = check(0, len(s) - 1)
        if left > mid:
            return True
        return check(left + 1, right)[0] > mid or check(left, right - 1)[0] == mid

    剑指 Offer II 020. 回文子字符串的个数

    题目描述

    给定一个字符串 s ,请计算这个字符串中有多少个回文子字符串。

    具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。

    剑指 Offer II 020. 回文子字符串的个数 - 力扣(LeetCode) (leetcode-cn.com)

    题解

    中心扩散

    def countSubstrings(self, s: str) -> int:
        n = len(s)
        #最多能向外扩散几步
        def check(l,r):
            count = 0
            while l >= 0 and r<n and s[l] == s[r]:
                count+=1
                l -= 1
                r += 1
            return count
        
        ret = 0
        for i in range(n):
            # 字串奇数长 中心为s[i]
            odd = check(i, i)
            # 字串偶数长 中心为s[i]s[i+1]这个也要比一比
            even = check(i, i + 1)
            ret += odd
            ret += even
        return ret

    动态规划

  • 相关阅读:
    Sky中国War3的旗帜
    2008流行趋势发布暨07届学生毕业秀(上海大学主办)
    随便写一下
    六一节——小朋友们快乐
    HEI
    Update my blog to improve my idea.
    由ipod引起的奇遇记
    加勒比海盗
    “老板娘”请客吃饭
    蚂蚁工坊
  • 原文地址:https://www.cnblogs.com/PiaYie/p/15732462.html
Copyright © 2011-2022 走看看