leetcode(19)字符串系列题目

541. 反转字符串 II

class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        p = 0
        while p < len(s):
            q = p + k
            s = s[:p] + s[p:q][::-1] + s[q:]
            p = p + k * 2
        return s

剑指 Offer 05. 替换空格

简单粗暴的一些方法:

class Solution:
    def replaceSpace(self, s: str) -> str:
        # return "%20".join(s.split())
        return "%20".join(s.split(' '))  # 等价

        s = re.sub(' ','%20',s)
        return s

从后往前遍历

class Solution:
    def replaceSpace(self, s: str) -> str:
        n = len(s)
        for k, v in enumerate(s[::-1]):
        print(k,v)
            if v == ' ':
                s = s[:n - k - 1] + '%20' + s[n - k:]
        return s

151. 颠倒字符串中的单词

分三步:
1.先翻转整个数组
2.再翻转单个单词
3.清除多余空格

class Solution:
    def reverseWords(self, s: str) -> str:
        s, n = list(s), len(s)
        def reverse(s, i, j):
            while i < j:
                s[i], s[j] = s[j], s[i]
                i += 1
                j -= 1
        def reverse_w(s):
            i = j = 0
            while i < n:
                while i < n and s[i] == ' ':  # 找到单词开头
                    i += 1
                j = i
                while j < n and s[j] != ' ':  # 找到单词结尾
                    j += 1
                reverse(s, i, j - 1)  # 注意是j - 1
                i = j
        def clean_space(s):
            i = j = 0  # 类似于快慢指针
            while j < n:
                while j < n and s[j] == ' ':  # 去除前面的空格
                    j += 1
                while j < n and s[j] != ' ':
                    s[i] = s[j]  # 即把快指针位置的值赋值给慢指针
                    i += 1
                    j += 1
                while j < n and s[j] == ' ':  # 删除中间位置的空格
                    j += 1
                if j < n:  # 在单词与单词之间放一个空格
                    s[i] = ' '
                    i += 1
            return ''.join(s[:i])
        reverse(s, 0, n - 1)
        reverse_w(s)
        return clean_space(s)

直接用spilt()函数,可以但不建议

class Solution:
    def reverseWords(self, s: str) -> str:
        s_list = s.split()
        # print(s_list)
        return ' '.join(s_list[::-1])

剑指 Offer 58 - II. 左旋转字符串

偷懒做法用切片:

class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        return s[n:]+s[:n]

或用“列表遍历拼接”和 “字符串遍历拼接”

class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        res = []
        for i in range(n, len(s)):
            res.append(s[i])
        for i in range(0, n):
            res.append(s[i])
        return ''.join(res)


class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        res = ''
        for i in range(n, len(s)):
            res += s[i]
        for i in range(0, n):
            res += s[i]
        return res

844. 比较含退格的字符串

双指针分别指向两个字符串的尾,存储#的个数,并跳过
注意:一次只跳过一个,且比较两个字符的时候要内嵌判断条件

class Solution:
    def backspaceCompare(self, s: str, t: str) -> bool:
        i, j = len(s) - 1, len(t) - 1
        skipS ,skipT = 0, 0
        while i >= 0 or j >= 0:
            while i >= 0:
                if s[i] == '#':
                    skipS += 1
                    i -= 1
                else:
                    if skipS == 0:
                        break
                    else:
                        i -= 1
                        skipS -= 1  # 一次只跳过一个
            while j >= 0:
                if t[j] == '#':
                    skipT += 1
                    j -= 1
                else:
                    if skipT == 0:
                        break
                    else:
                        j -= 1
                        skipT -= 1
            if i >= 0 and j >= 0 :  # 限制i >= 0 and j >= 0
                if s[i] != t[j]:  # 要内嵌判断条件
                    return False  
            elif i >= 0 or j >= 0:  # 其中一个已经遍历完了另一个还没遍历完
                return False
            i -= 1
            j -= 1
        return True

168. Excel表列名称

class Solution:
    def convertToTitle(self, columnNumber: int) -> str:
        res = ''
        while columnNumber:
            columnNumber -= 1  # 注意每次都要-1,因为A要与1对应而不是0
            n = columnNumber % 26
            s = chr(n + 65)  #ASCII码转成大写字符
            res = s + res # 左加才是加在字符串后面
            columnNumber //= 26
        return res

171. Excel 表列序号

ord(columnTitle[0]) - 64得到第一位字母对应的数,后面再*26 +ord(columnTitle[i]) - 64

class Solution:
    def titleToNumber(self, columnTitle: str) -> int:
        cur = ord(columnTitle[0]) - 64
        for i in range(1, len(columnTitle)):
            cur = cur * 26 + ord(columnTitle[i]) - 64
        return cur

859. 亲密字符串

分三种情况讨论:

  1. 两字符串长度不相等, 返回false
  2. 两字符串相等的时候, 有重复的元素就返回true
  3. 两字符串有且仅有两个不相等的地方, 判断它们交换后是否相等
class Solution:
    def buddyStrings(self, s: str, goal: str) -> bool:
        if len(s) != len(goal):
            return False
        if s == goal and len(set(s)) < len(goal):
            return True
        diff = []
        for i in range(len(s)):
            if s[i] != goal[i]:
                diff.append(i)
        if len(diff) == 2 and s[diff[0]] == goal[diff[1]] and s[diff[1]] == goal[diff[0]]:
            return True
        else:
            return False

1768. 交替合并字符串

class Solution:
    def mergeAlternately(self, word1: str, word2: str) -> str:
        res = []
        for x, y in zip_longest(word1, word2):
            if x: res.append(x)
            if y: res.append(y)
        return ''.join(res)

451. 根据字符出现频率排序

根据字典的value进行排序

class Solution:
    def frequencySort(self, s: str) -> str:
        cnt = Counter(s)
        res = ''
        for c, v in sorted(list(cnt.items()), key = lambda x:-x[1]):
            res += c * v
        return res

1239. 串联字符串的最大长度

不用回溯,维护以下第i个前可用的序列组合,然后把第i个加进去,如果可用就放进去继续往后求

class Solution:
    def maxLength(self, arr: List[str]) -> int:
        res = 0
        tmp = ['']
        for s in arr:
            cur = []  # 存到目前的可行解
            for t in tmp:
                concat = s + t
                if len(set(concat)) == len(concat):
                    res = max(res, len(concat))
                    cur.append(concat)   
                print(cur)
            tmp += cur
        return res

1773. 统计匹配检索规则的物品数量

先用字典存规则的序号

class Solution:
    def countMatches(self, items: List[List[str]], ruleKey: str, ruleValue: str) -> int:
        rule_dict = {'type':0, 'color':1, 'name':2}
        rule_no = rule_dict[ruleKey]
        res = 0
        for i in range(len(items)):
            if items[i][rule_no] == ruleValue:
                res += 1
        return res

784. 字母大小写全排列

把当前字符的大小写拼在之前列表的每个字符串后面

class Solution:
    def letterCasePermutation(self, s: str) -> List[str]:
        res = ['']
        for ch in s:
            if ch.isalpha():
                res = [r + ch.lower() for r in res] + [r + ch.upper() for r in res]
            else:
                res = [r + ch for r in res]
        return res

481. 神奇字符串

找规律:s 看成是由「1 组」和「2 组」交替组成的,重点在于每组内的数字是一个还是两个,这可以从 s 自身上知道

class Solution:
    def magicalString(self, n: int) -> int:
        nums = [1, 2, 2]
        i = 2
        while i < n:
            cur = 3 - nums[-1]
            nums += [cur] * nums[i]
            i += 1
        return nums[:n].count(1)

1647. 字符频次唯一的最小删除次数

先统计字符个数,然后遍历把44332变成43210

class Solution:
    def minDeletions(self, s: str) -> int:
        cnt = Counter(s)
        nums = sorted(list(cnt.values()), reverse = True)
        res = sum(nums)
        for i in range(1, len(nums)):
            if nums[i] >= nums[i - 1]:
                nums[i] = max(nums[i - 1] - 1, 0)
        return res - sum(nums)

1668. 最大重复子字符串

遍历次数,直接判断,这个次数的word有没有在seq里面出现

class Solution:
    def maxRepeating(self, sequence: str, word: str) -> int:
        for i in range(len(sequence)//len(word), -1, -1):
            print(word * i)
            if word * i in sequence:
                return i

125. 验证回文串

双指针,里面的判断部分还可以再优化一下

class Solution:
    def isPalindrome(self, s: str) -> bool:
        s = s.lower()
        # print(s)
        left, right = 0, len(s) - 1
        while left <= right:
            while left < len(s) and not (s[left].isalpha() or s[left].isdigit()):
                left += 1
            while right >= 0 and not (s[right].isalpha() or s[right].isdigit()):
                right -= 1
            if left == len(s) or right == -1:
                return True
            if s[left] != s[right]:
                return False
            left += 1
            right -= 1
        return True

1106. 解析布尔表达式

从左到右遍历表达式 expression,对于遍历到的每个字符 cc:

如果 e 是 "tf!&|" 中的一个,直接将其入栈;
如果 e 是右括号 ')',将栈中元素依次出栈,直到遇到操作符 '!' 或 '&' 或 '|'。过程中用变量 t 和 f 记录出栈字符中 't' 和 'f' 的个数。最后根据出栈字符的个数和操作符计算得到新的字符 't' 或 'f',并将其入栈。
遍历完表达式 expression 后,栈中只剩下一个字符,如果是 't',返回 true,否则返回 false。

class Solution:
    def parseBoolExpr(self, expression: str) -> bool:
        stk = []
        for e in expression:
            if e in 'tf!&|':
                stk.append(e)
            elif e == ')':
                t = f = 0
                while stk[-1] in 'tf':
                    t += stk[-1] == 't'
                    f += stk[-1] == 'f' 
                    stk.pop()
                match stk.pop():
                    case '!':
                        c = 'f' if t else 't'
                    case '&':
                        c = 'f' if f else 't'
                    case '|' :
                        c = 't' if t else 'f'
                stk.append(c)
        return stk[0] == 't'

1678. 设计 Goal 解析器

直接进行模拟

class Solution:
    def interpret(self, command: str) -> str:
        i = 0
        res = ''
        while i < len(command):
            if command[i] == 'G':
                res += 'G'
                i += 1
            elif command[i] == '(' and command[i + 1] == ')':
                res += 'o'
                i += 2
            elif command[i] == '(' and command[i + 1] == 'a':
                res += 'al'
                i += 4
        return res

1684. 统计一致字符串的数目

写法一:集合包含可以写作:set(allowed) >= set(w)

class Solution:
    def countConsistentStrings(self, allowed: str, words: List[str]) -> int:
        return sum([set(allowed) >= set(w) for w in words])

写法二:或者用all判断所有字符都在allowed里

class Solution:
    def countConsistentStrings(self, allowed: str, words: List[str]) -> int:
        allowed = set(allowed)
        return sum(all(ch in allowed for ch in w) for w in words)

写法三:自己写的,不够简约

class Solution:
    def countConsistentStrings(self, allowed: str, words: List[str]) -> int:
        res = 0
        for w in words:
            for i, ch in enumerate(w):
                if ch not in allowed:
                    break
                if i == len(w) - 1:
                    res += 1 
        return res

1704. 判断字符串的两半是否相似

分别记录前后的元音字母个数

class Solution:
    def halvesAreAlike(self, s: str) -> bool:
        n = len(s)
        dic = 'aeiouAEIOU'
        cnt1, cnt2 = 0, 0
        for i in range(n//2):
            if s[i] in dic:
                cnt1 += 1
        for i in range(n//2,n):
            if s[i] in dic:
                cnt2 += 1
        return cnt1 == cnt2

722. 删除注释

注意:while循环的i += 1写在外面,因为遍历到的字符可能在注释内,但是也要继续往下遍历
curline = []用数组比用字符效率更好

class Solution:
    def removeComments(self, source: List[str]) -> List[str]:
        flag = False  # 不在注释内
        res = []
        for line in source:
            i = 0
            if not flag: curline = []
            while i < len(line):
                if line[i: i + 2] == '/*' and not flag:  # 块注释开始
                    flag = True
                    i += 1
                elif line[i: i + 2] == '*/' and flag:  # 块注释结束
                    flag = False
                    i += 1
                elif line[i: i + 2] == '//' and not flag:  # 行注释开始
                    break
                elif not flag:
                    curline.append(line[i])
                i += 1
            if curline and not flag:
                res.append(''.join(curline))
        return res

791. 自定义字符串排序

先把order里有的字符全部按顺序放进去,然后再把s中多余的字符放进去

class Solution:
    def customSortString(self, order: str, s: str) -> str:
        cnt = Counter(s)
        res = ''
        for ch in order:
            if ch in s:
                res += ch * cnt[ch]
        for ch in cnt:
            if ch not in res:
                res += ch * cnt[ch]
        return res

792. 匹配子序列的单词数

从 s 的第一个字符开始遍历,假设当前字符为 'a',从 'a' 开头的桶中取出所有单词。对于取出的每个单词,如果此时单词长度为 1,说明该单词已经匹配完毕,将答案加 1;否则将单词的首字母去掉,然后放入下一个字母开头的桶中,比如对于单词 "acd",去掉首字母 'a' 后,将其放入 'c' 开头的桶中。这一轮结束后,分桶结果变为:

c: ["cd", "ce"]
b: ["bb"]

class Solution:
    def numMatchingSubseq(self, s: str, words: List[str]) -> int:
        dic = defaultdict(deque)
        for w in words:
            dic[w[0]].append(w)
        res = 0
        for ch in s:
            for _ in range(len(dic[ch])):
                cur = dic[ch].popleft()
                if len(cur) == 1:
                    res += 1
                else:
                    dic[cur[1]].append(cur[1:])
        return res

1758. 生成交替二进制字符串的最少操作数

解题关键:变成以1开头和变成以0开头的操作数之和为字符串的总长度n

class Solution:
    def minOperations(self, s: str) -> int:
        cnt = 0
        n = len(s)
        for i in range(n):
            if int(s[i]) == i % 2:
                cnt += 1
        return min(cnt, n - cnt)

809. 情感丰富的文字

注意判断w的重复个数比s的多的情况

class Solution:
    def expressiveWords(self, s: str, words: List[str]) -> int:
        def check(s, t):
            i, j = 0, 0
            while i < len(s) and j < len(t):
                if s[i] != t[j]:
                    return 0
                cnt_s = 0
                while i < len(s) - 1 and s[i] == s[i + 1]:
                    i += 1
                    cnt_s += 1
                cnt_t = 0
                while j < len(t) - 1 and t[j] == t[j + 1]:
                    j += 1
                    cnt_t += 1
                
                if cnt_t < cnt_s < 2 or cnt_t > cnt_s:
                    return 0
                i += 1
                j += 1
            if i == len(s) and j == len(t):
                return 1
            return 0
        return sum(check(s, w) for w in words)

1796. 字符串中第二大的数字

用变量分别记录最大和第二大,依次遍历

class Solution:
    def secondHighest(self, s: str) -> int:
        fir, sec = -1, -1
        for c in s:
            if c.isdigit():
                cur = int(c)
                if cur > fir:
                    fir, sec = cur, fir
                elif sec < cur < fir:
                    sec = cur
        return sec

6253. 回环句

先对句子拆分,再比较每个单词的最后一个字母与其后一个单词的第一个字母
注意因为最后一个单词的后一个单词是第一个单词,因此使用s[(i + 1) % len(s)]来表示后一个单词

class Solution:
    def isCircularSentence(self, sentence: str) -> bool:
        s = sentence.split(' ')
        for i, w in enumerate(s):
            if w[-1] != s[(i + 1) % len(s)][0]:
                return False
        return True

1781. 所有子字符串美丽值之和

遍历以i开始的子字符串就只要计算一次cnt

class Solution:
    def beautySum(self, s: str) -> int:
        res, n = 0, len(s)
        for i in range(n):
            cnt = Counter()
            for j in range(i, n):
                cnt[s[j]] += 1
                res += max(cnt.values()) - min(cnt.values())
        return res

1832. 判断句子是否为全字母句

直接统计字典里元素的个数

class Solution:
    def checkIfPangram(self, sentence: str) -> bool:
        return len(Counter(sentence)) == 26

参考资料:
面试题58 - II. 左旋转字符串(切片 / 列表 / 字符串,清晰图解)

posted @   YTT77  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
点击右上角即可分享
微信分享提示