字符串试题(Python实现)

目录

1. 判断是否为回文字符串(双指针)

2. 反转字符串

3. 字符串变形(字母大小写切换)

4. 最长回文子串

5. 无重复字符的最长子串

6. 最长公共子串

7. 最长公共前缀

8. 最长的括号子串

9. 括号生成

10. 最小覆盖子串

11. 重排字符串

12. 字符串的排列(递归/回溯)

13. 把数字翻译成字符串(DP)

14. 数字字符串转化成IP地址(dfs+递归/回溯)

15. 验证IP地址

16. 正则表达式匹配(DP)

17. 比较版本号

18. 大数加法


1. 判断是否为回文字符串(双指针)

class Solution:
    def judge(self , str: str) -> bool:
        left = 0
        right = len(str)-1
        while left < right:
            if str[left] != str[right]:
                return False
            left += 1
            right -= 1
        return True

2. 反转字符串

class Solution:
    def solve(self , str: str) -> str:
        res = ""
        for i in range(len(str)-1, -1, -1):
            res += str[i]
        return res
# Python特性方法:return str[::-1]

3. 字符串变形(字母大小写切换)

class Solution:
    def trans(self , s: str, n: int) -> str:
        if n == 0: return s
        res = ""
        for i in range(n):
            if s[i] >= 'A' and s[i] <= 'Z':
                res += chr(ord(s[i]) - ord('A') + ord('a'))
            elif s[i] >= 'a' and s[i] <= 'z':
                res += chr(ord(s[i]) - ord('a') + ord('A'))
            else:
                res += s[i]
        res = list(res.split(' '))[::-1]
        return ' '.join(res)

4. 最长回文子串

暴力法:

class Solution:
    # 验证是否是回文
    def Valid(self, s: str, l: int, r: int) -> bool:
        while l < r:
            if s[l] != s[r]:
                return False
            l += 1
            r -= 1
        return True
    def getLongestPalindrome(self , A: str) -> int:
        # 记录最长回文子串的长度
        maxlen = 1
        # 记录最长回文子串的起始点
        begin = 0
        for i in range(len(A)-1):
            for j in range(len(A)-1, i, -1):
                if j-i+1 > maxlen and self.Valid(A, i, j):
                    maxlen = j-i+1
                    begin = i
                    break
        # 最长回文子串为:A[begin:begin+maxlen]
        return maxlen

中心扩散法:

class Solution:
    # 中心扩散
    def fun(self, s: str, begin: int, end: int) -> int:
        # 每个中心点开始扩散
        while begin >= 0 and end <= len(s)-1 and s[begin] == s[end]:
            begin -= 1
            end += 1
        # 返回长度
        return end - begin - 1
    def getLongestPalindrome(self , A: str) -> int:
        maxlen = 1
        # 以每个点为中心
        for i in range(len(A) - 1):
            # 分奇数长度 和 偶数长度向两边扩展
            maxlen = max(maxlen, max(self.fun(A, i, i), self.fun(A, i, i+1)))
        return maxlen
———————— E N D ———————— E N D ———————— E N D ————————
    # 若获取最长子串的方法
    def getLongestPalindrome(self , A: str) -> int:
        maxlen = 1
        begin = 0
        # 以每个点为中心
        for i in range(len(A) - 1):
            max_now = max(self.fun(A, i, i), self.fun(A, i, i+1))
            if maxlen < max_now:
                maxlen = max_now
                begin = i - (maxlen-1)//2
        return A[begin:begin+maxlen]

5. 无重复字符的最长子串

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        if len(s) <= 1: return len(s)
        ss = set()
        start = 0
        res = 0
        for i in range(len(s)):
            while s[i] in ss:
                ss.remove(s[start])
                start += 1
            ss.add(s[i])
            res = max(res, i - start + 1)
        return res

6. 最长公共子串

class Solution:
    def LCS(self , str1: str, str2: str) -> str:
        # 让str1为较长的字符串
        if len(str1) < len(str2):
            str1 ,str2 = str2, str1
        res = ""
        length = 0
        for i in range(len(str1)):
            if str1[i-length : i+1] in str2:
                res = str1[i-length: i+1]
                length += 1
        return res

7. 最长公共前缀

class Solution:
    def longestCommonPrefix(self , strs: List[str]) -> str:
        n = len(strs)
        if n == 0: return ""
        for i in range(len(strs[0])):
            # 取第一个元素的值作为对比
            tmp = strs[0][i]
            for j in range(1,n):
                # 如果已经达到最大长度 或 元素值不相同
                if i == len(strs[j]) or strs[j][i] != tmp:
                    return strs[0][0:i]
        return strs[0]

zip(*xx) 将同下标元素打包为一个元组,分别存入set进行验证即可

class Solution:
    def longestCommonPrefix(self , strs: List[str]) -> str:
        res = ''
        # zip将同下标元素打包
        for i in zip(*strs):
            if len(set(i)) == 1:
                res += i[0]
            else:
                break
        return res

8. 最长的括号子串

class Solution:
    def longestValidParentheses(self, s: str) -> int:
        res = 0
        # 记录上一次连续括号结束的位置
        start = -1
        st = []
        for i in range(len(s)):
            # 左括号入栈
            if s[i] == "(":
                st.append(i)
            # 右括号
            else:
                # 如果右括号时栈为空,不合法,设置为结束位置
                if len(st) == 0:
                    start = i
                else:
                    # 弹出左括号
                    st.pop()
                    # 栈中还有左括号,说明右括号不够,减去栈顶位置就是长度
                    if len(st) != 0:
                        res = max(res, i - st[-1])
                    # 栈中没有括号,说明左右括号行号,减去上一次结束的位置就是长度
                    else:
                        res = max(res, i - start)
        return res

9. 括号生成

class Solution:
    def recursion(self, left: int, right: int, tmp: str, res: List[str], n: int):
        if left == n and right == n:
            res.append(tmp)
            return
        # 左括号
        if left < n:
            self.recursion(left + 1, right, tmp + "(", res, n)
        # 右括号
        if right < n and left > right:
            self.recursion(left, right + 1, tmp + ")", res, n)

    def generateParenthesis(self , n: int) -> List[str]:
        res = []
        tmp = ""
        self.recursion(0, 0, tmp, res, n)
        return res

10. 最小覆盖子串

class Solution:
    # 检查是否覆盖(存在有小于0的说明未覆盖)
    def check(self, map: dict()) -> bool:
        for key, value in map.items():
            if value < 0:
                return False
        return True
    def minWindow(self , S: str, T: str) -> str:
        count = len(S) + 1
        map = dict()
        for i in range(len(T)):
            if T[i] in map:
                map[T[i]] -= 1
            else:
                map[T[i]] = -1
        slow = 0
        fast = 0
        left = -1
        right = -1
        while fast < len(S):
            c = S[fast]
            if c in map:
                map[c] += 1
            while self.check(map):
                if count > fast -slow + 1:
                    count = fast - slow + 1
                    left = slow
                    right = fast
                c = S[slow]
                if c in map:
                    map[c] -= 1
                # 窗口缩小
                slow += 1
            fast += 1
        if left == -1: return ""
        return S[left:right+1]

11. 重排字符串

import collections

class Solution:
    def rearrangestring(s: str):
        n = len(s)
        
        # 排除特殊情况
        if s is None or n <= 1:
            return s
        
        # 统计s中每个字符出现次数
        count = collections.Counter(s)
        maxCounter = max(count.values())
        # 判断是否能够填充
        if maxCounter > (n + 1)//2:
            return ""

        # 按字符出现次数
        count = sorted(count.items(), key = lambda x: x[-1])

        data = []
        for k, v in count:
            data += [k]*v
        
        res = ["" for _ in range(len(s))]
        res[::2] = data[:(n + 1) // 2]
        res[1::2] = data[(n + 1) // 2:]
        
        return "".join(res)

12. 字符串的排列(递归/回溯)

class Solution:
    def recursion(self, res: List[str], strs: str, tmp: str, vis: List[int]):
        if len(tmp) == len(strs):
            res.append(tmp)
            return
        for i in range(len(strs)):
            if vis[i] == 1:
                continue
            if i > 0 and strs[i-1] == strs[i] and not vis[i-1]:
                continue
            # 标记为使用过
            vis[i] = 1
            # 加入临时字符串
            tmp += strs[i]
            self.recursion(res, strs, tmp, vis)
            # 回溯
            vis[i] = 0
            tmp = tmp[:-1]
    def Permutation(self , str: str) -> List[str]:
        str ="".join((lambda x:(x.sort(), x)[1])(list(str)))
        vis = [0]*len(str)
        res = []
        tmp = ""
        self.recursion(res, str, tmp, vis)
        return res

13. 把数字翻译成字符串(DP)

class Solution:
    def solve(self, nums: str) -> int:
        # 排除0
        if nums == "0":
            return 0
        # 排除只有一种可能的10 和 20
        if nums == "10" or nums == "20":
            return 1
        # 当0的前面不是1或2时,无法译码,0种
        for i in range(1, len(nums)):
            if nums[i] == "0":
                if nums[i - 1] != "1" and nums[i - 1] != "2":
                    return 0
        # 辅助数组初始化为1
        dp = [1 for i in range(len(nums) + 1)]
        for i in range(2, len(nums) + 1):
            # 在11-19,21-26之间的情况
            if (nums[i - 2] == "1" and nums[i - 1] != "0") or (
                nums[i - 2] == "2" and nums[i - 1] > "0" and nums[i - 1] < "7"):
                dp[i] = dp[i - 1] + dp[i - 2]
            else:
                dp[i] = dp[i - 1]
        return dp[len(nums)]

14. 数字字符串转化成IP地址(dfs+递归/回溯)

class Solution:
    def restoreIpAddresses(self , s: str) -> List[str]:
        def isNum(num):
            # 排除以 0 开头的情况
            if num and str(int(num)) == num and int(num) >= 0 and int(num) <= 255:
                return True
            else:
                return False
        res = []
        for i in range(1,4):
            w1 = s[:i]
            if not isNum(w1):
                continue
            
            for j in range(i+1, i+4):
                w2 = s[i:j]
                if not isNum(w2):
                    continue
                
                for k in range(j+1, j+4):
                    w3 = s[j:k]
                    w4 = s[k:]
                    if not isNum(w3) or not isNum(w4):
                        continue
                    
                    res.append(w1 + '.' + w2 + '.' + w3 + '.' + w4)
        return res

法二:

class Solution:
    def __init__(self):
        self.res = []
        self.s = ""
        self.nums = ""
 
    # step表示第几个数字,index表示字符串下标
    def dfs(self, step: int, index: int):
        # 当前分割出的字符串
        cur = ""
        # 分割出了四个数字
        if step == 4:
            # 下标必须走到末尾
            if index != len(self.s):
                return
            self.res.append(self.nums)
        else:
            i = index
            # 最长遍历3位
            while i < index + 3 and i < len(self.s):
                cur += self.s[i]
                # 转数字比较
                num = int(cur)
                temp = self.nums
                # 不能超过255且不能有前导0
                if num <= 255 and (len(cur) == 1 or cur[0] != "0"):
                    # 添加点
                    if step - 3 != 0:
                        self.nums += cur + "."
                    else:
                        self.nums += cur
                    # 递归查找下一个数字
                    self.dfs(step + 1, i + 1)
                    # 回溯
                    self.nums = temp
                i += 1
 
    def restoreIpAddresses(self, s: str) -> List[str]:
        self.s = s
        self.dfs(0, 0)
        return self.res

15. 验证IP地址

class Solution:
    def isIPv4(self, IP: str) -> bool:
        s = IP.split('.')
        if len(s) != 4:
            return False
        for i in range(len(s)):
            # 每位不可缺省
            if len(s[i]) == 0:
                return False
            # 1-3位数字,前缀不为0
            if len(s[i]) > 3 or (len(s[i]) > 1 and s[i][0] == '0'):
                return False
            # 每位均为数字
            for j in range(len(s[i])):
                if s[i][j] < '0' or s[i][j] > '9':
                    return False
            num = int(s[i])
            if num < 0 or num > 255:
                return False
        return True
    def isIPv6(self, IP: str) -> bool:
        s = IP.split(':')
        if len(s) != 8:
            return False
        for i in range(len(s)):
            # 每位不可缺省
            if len(s[i]) == 0 or len(s[i]) > 4:
                return False
            for j in range(len(s[i])):
                if not (s[i][j].isdigit() or s[i][j] >= 'a' and s[i][j] <= 'f' or s[i][j] >= 'A' and s[i][j] <= 'F'):
                    return False
        return True

    def solve(self , IP: str) -> str:
        if len(IP) == 0: return "Neither"
        if self.isIPv4(IP): return "IPv4"
        if self.isIPv6(IP): return "IPv6"
        return "Neither"

正则表达式法:

import re
class Solution:
    def solve(self, IP: str) -> str:
        # 0-255,前缀不为0
        ipv4 = "(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"
        # 0-9 a-f A-F,位数为1-4位
        ipv6 = "([0-9a-fA-F]{1,4}\:){7}([0-9a-fA-F]{1,4})$"
        ipv4 = re.compile(ipv4)
        ipv6 = re.compile(ipv6)
        # 正则匹配函数
        if ipv4.match(IP):
            return "IPv4"
        if ipv6.match(IP):
            return "IPv6"
        return "Neither"

16. 正则表达式匹配(DP)

class Solution:
    def match(self, str: str, pattern: str) -> bool:
        n1 = len(str)
        n2 = len(pattern)
        # dp[i][j]表示str前i个字符和pattern前j个字符是否匹配
        dp = [[False] * (n2 + 1) for i in range(n1 + 1)]
        # 两个都为空串自然匹配
        dp[0][0] = True
        # 初始化str为空的情况,字符串下标从1开始
        for i in range(2, n2 + 1):
            # 可以让自己前面个字符重复0次
            if pattern[i - 1] == "*":
                # 与再前一个能够匹配空串有关
                dp[0][i] = dp[0][i - 2]
        # 遍历str每个长度
        for i in range(1, n1 + 1):
            # 遍历pattern每个长度
            for j in range(n2 + 1):
                # 当前字符不为*,用.去匹配或者字符直接相同
                if pattern[j - 1] != "*" and (
                    pattern[j - 1] == "." or pattern[j - 1] == str[i - 1]
                ):
                    dp[i][j] = dp[i - 1][j - 1]
                # 当前的字符为*
                elif j >= 2 and pattern[j - 1] == "*":
                    # 若是前一位为.或者前一位可以与这个数字匹配
                    if pattern[j - 2] == "." or pattern[j - 2] == str[i - 1]:
                        # 转移情况
                        dp[i][j] = dp[i - 1][j] or dp[i][j - 2]
                    else:
                        # 不匹配
                        dp[i][j] = dp[i][j - 2]
        return dp[n1][n2]

17. 比较版本号

class Solution:
    def compare(self , version1: str, version2: str) -> int:
        v1 = version1.split('.')
        v2 = version2.split('.')
        for i in range(max(len(v1), len(v2))):
            num1 = int(v1[i]) if i < len(v1) else 0
            num2 = int(v2[i]) if i < len(v2) else 0

            if num1 > num2:
                return 1
            elif num1 < num2:
                return -1
        return 0

18. 大数加法

class Solution:
    def solve(self , s: str, t: str) -> str:
        if len(s) == 0: return t
        if len(t) == 0: return s
        # s作为长
        if len(s) < len(t): s,t = t,s
        # 进位标志
        carry = 0
        for i in range(len(s)-1,-1,-1):
            tmp = ord(s[i]) - ord('0') + carry
            j = i - len(s) + len(t)
            if j >= 0:
                tmp += ord(t[j]) - ord('0')
            carry = int(tmp / 10)
            tmp %= 10
            s = s[:i] + chr(tmp + ord('0')) + s[i+1:]
        if carry == 1: s = '1' + s
        return s

猜你喜欢

转载自blog.csdn.net/qq_52057693/article/details/128886566
今日推荐