算法通关村第十二关:字符串经典基础面试题

字符串经典题目

反转的问题

LeetCode344、541、917、151、557

反转字符串

LeetCode344. 反转字符串
https://leetcode.cn/problems/reverse-string/

思路分析

最基本的反转题,使用双指针进行反转

反转前字符数组
s[0],s[1],s[2] … s[n-1]
反转后字符数组
s[n-1],s[n-2],s[n-3] … s[0]

=> s[i]和s[j]交换,i+j = n-1 => s[i]和s[n-i-1]交换

双指针解法:

  • left指向字符数组首元素,right指向字符数组尾元素
  • left<right时
    交换s[left]和s[right]
    left右移一位
    right左移一位
  • left>=right,反转结束

代码实现

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

k个一组反转

LeetCode541. 反转字符串 II
https://leetcode.cn/problems/reverse-string-ii/

思路分析

将需要反转的子字符串拆分处理,每个子字符串的开始下标为2kn(n=0,1,…),长度为k,即 [ 2kn, 2k*n+k]
反转每个下标从2k的倍数开始的,长度为k的子串;若该子串长度不足k,则反转整个子串

代码实现


class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        if not s or len(s) <= 1:
            return s
        char_list = list(s)
        for i in range(0, len(char_list), 2*k):
            char_list[i:i+k] = reversed(char_list[i:i+k])
        return "".join(char_list)
        

class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        def reverse_arr(arr):
            if not arr or len(arr) <= 1:
                return arr
            left, right = 0, len(arr)-1
            while left < right:
                arr[left], arr[right] = arr[right], arr[left]
                left += 1
                right -= 1
            return arr


        if not s or len(s) <= 1:
            return s
        char_list = list(s)
        for i in range(0, len(char_list), 2*k):
            char_list[i:i+k] = reverse_arr(char_list[i:i+k])
        return "".join(char_list)
        

仅仅反转字母

LeetCode917. 仅仅反转字母
https://leetcode.cn/problems/reverse-only-letters/

思路分析

方法1:使用栈

将s中的所有字母单独存入栈中,出栈等于对字母反序操作(或者数组存储,并反序数组)
遍历s的所有字符,如果是字母我们选择栈顶元素输出

方法2:双指针

一个接一个输出s的所有字符,当遇到一个字母时,我们希望找到逆序遍历字符串的下一个字母

所以我们这么做:维护一个指针 j 从后往前遍历字符串,当需要字母时就使用它

代码实现

方法1:使用栈

class Solution:
    def reverseOnlyLetters(self, s: str) -> str:
        # 方法1:使用栈
        if not s or len(s) <= 1:
            return s

        # 收集字符串中所有的字母
        letters = []
        for i in s:
            if i.isalpha():
                letters.append(i)
        # 反转字符串中字母
        char_list = list(s)
        for i in range(0, len(char_list)):
            if char_list[i].isalpha():
                char_list[i] = letters.pop()

        return "".join(char_list)
class Solution:
    def reverseOnlyLetters(self, s: str) -> str:
        # 方法1:使用栈
        letters = []
        for c in s:
            if c.isalpha():
                letters.append(c)

        ans = ''
        for c in s:
            ans += letters.pop() if c.isalpha() else c

        return ans

方法2:双指针

class Solution:
    def reverseOnlyLetters(self, s: str) -> str:
        # 方法2:双指针
        char_list = list(s)
        n = len(char_list)
        left, right = 0, n - 1

        while left < right:
            while left < n and not char_list[left].isalpha():
                left += 1
            while right >= 0 and not char_list[right].isalpha():
                right -= 1
            if left < right:
                char_list[left], char_list[right] = char_list[right], char_list[left]
                left += 1
                right -= 1

        return "".join(char_list)
class Solution:
    def reverseOnlyLetters(self, s: str) -> str:
        # 方法2:双指针
        if not s:
            return s

        ans = ''
        j = len(s) - 1

        for i in range(len(s)):
            if s[i].isalpha():
                while not s[j].isalpha():
                    j -= 1
                ans += s[j]
                j -= 1
            else:
                ans += s[i]

        return ans

反转字符串里的单词

LeetCode151. 反转字符串中的单词
https://leetcode.cn/problems/reverse-words-in-a-string/

思路分析

方法1:使用语言提供的方法实现

  • split(拆分)将字符串按空格分割成字符串数组
  • reverse/reversed(反转)将字符串数组进行反转
  • join(连接)将字符串数组拼接成一个字符串

其他,strip() 去除开头和末尾的空白字符,注:split()会自动去除开头和末尾的空白字符

print(" 1 2 3 4     5     ".split())  # ['1', '2', '3', '4', '5']
print(" 1 2 3 4     5     ".split(' '))  # ['', '1', '2', '3', '4', '', '', '', '', '5', '', '', '', '', '']

方法2:自己实现上述功能

执行步骤

  1. 去除空白字符,去除开头、末尾、中间多余(单词之间只保留一个)空白字符
  2. 反转整个字符串
  3. 反转每个单词
  4. 连接单词

在这里插入图片描述

代码实现

方法1:使用语言提供的方法实现

class Solution:
    def reverseWords(self, s: str) -> str:
        words = s.split()
        words.reverse()
        return " ".join(words) # 精简 return " ".join(reversed(s.split()))

方法2:自己实现上述功能

class Solution:
    def trim_space(self, s):
        # 去除开头、结尾空白字符,单词之间只保留一个空白字符
        left, right = 0, len(s) - 1
        # 去除开头空白字符
        while s[left] == ' ':
            left += 1
        # 去除结尾空白字符
        while s[right] == ' ':
            right -= 1
        # 去除字符串间多余空白字符
        output = []
        while left <= right:
            if s[left] != ' ':
                output.append(s[left])
            elif output[-1] != ' ':
                output.append(s[left])
            left += 1

        return output

    def reverse(self, arr: list, left: int, right: int):
        while left <= right:
            arr[left], arr[right] = arr[right], arr[left]
            left += 1
            right -= 1

    def reverse_each_word(self, arr: list):
        n = len(arr)
        start = 0
        end = 0
        while start < n:
            # 找到单词的末尾
            while end < n and arr[end] != ' ':
                end += 1
            # 反转单词
            self.reverse(arr, start, end - 1)
            # 更新start,寻找下一个单词
            start = end + 1
            end += 1

    def reverseWords(self, s: str) -> str:
        # 方法2:自己的方法实现
        letters = self.trim_space(s)
        self.reverse(letters, 0, len(letters) - 1)
        self.reverse_each_word(letters)
        return "".join(letters)

验证回文串

LeetCode125. 验证回文串
https://leetcode.cn/problems/valid-palindrome/

思路分析

先转换成字符数组,然后使用双指针方法从两头到中间比较

代码实现

class Solution:
    def isPalindrome(self, s: str) -> bool:
        letters = []
        for i in s:
            if 'a' <= i <= 'z' or '0' <= i <= '9':
                letters.append(i)
            elif 'A' <= i <= 'Z':
                letters.append(i.lower())

        left, right = 0, len(letters) - 1
        while left < right:
            if letters[left] != letters[right]:
                return False
            left += 1
            right -= 1
        return True

代码简化

class Solution:
    def isPalindrome(self, s: str) -> bool:
        letters = "".join(ch.lower() for ch in s if ch.isalnum())
        left, right = 0, len(letters) - 1
        while left < right:
            if letters[left] != letters[right]:
                return False
            left += 1
            right -= 1
        return True

字符串中第一个唯一字符

LeetCode387. 字符串中的第一个唯一字符
https://leetcode.cn/problems/first-unique-character-in-a-string/

提示:
1 <= s.length <= 105
s 只包含小写字母

思路分析

可以对字符串进行两次遍历
第一次遍历,使用哈希映射统计出字符串中每个字符出现的次数
第二次遍历,只要遍历到了只出现一次的字符,就返回它的索引,否则在遍历结束后返回 -1

代码实现

class Solution:
    def firstUniqChar(self, s: str) -> int:
        frequency = {}
        for i in s:
            if i in frequency:
                frequency[i] += 1
            else:
                frequency[i] = 1
        for i in range(len(s)):
            if frequency[s[i]] == 1:
                return i
        return -1

代码简化

class Solution:
    def firstUniqChar(self, s: str) -> int:
        frequency = collections.Counter(s)
        for i, ch in enumerate(s):
            if frequency[ch] == 1:
                return i
        return -1

判定是否互为字符重排

LeetCode242. 有效的字母异位词
https://leetcode.cn/problems/valid-anagram/

给定两个字符串S1和S2,请编写一个程序确定其中一个字符串的字符重新排列后,能否编程另一个字符串

思路分析

方法1:排序法

将两个字符串全部从小到达或者从大到小排列,然后在逐个位置比较,这时候不管两个原始字符串是什么,都可以判断出来

方法2:使用哈希

如果一个字符串经过重新排列后,能够变成另外一个字符串,那么它们的每个不同字符的出现次数是相同的

代码实现

方法1:排序法

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        if len(s) != len(t):
            return False
        sorted_s = "".join(sorted(s))
        sorted_t = "".join(sorted(t))

        return sorted_s == sorted_t

注:python 中 sorted(‘cba’) 执行返回 [‘a’, ‘b’, ‘c’]

方法2:使用哈希

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        frequency_s = collections.Counter(s)
        frequency_t = collections.Counter(t)
        
        if sorted(frequency_s.keys()) != sorted(frequency_t.keys()):
            return False
        for i in frequency_s:
            if frequency_s[i] != frequency_t[i]:
                return False
        return True
class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        if len(s) != len(t):
            return False

        table = [0] * 26

        for ch in s:
            table[ord(ch) - ord('a')] += 1

        for ch in t:
            index = ord(ch) - ord('a')
            table[index] -= 1
            if table[index] < 0:
                return False

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值