算法&数据结构(一):字符串

leetcode:3. 无重复字符的最长子串

问题描述:给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

解法:滑动窗口,元素如果不在字典里面,就右移右边界(扩大);元素在字典里面,就右移左边界(缩小)。通过右边界的指针循环遍历,直到右边界达到末尾。因为左边界最多比右边界在右边一位,因而不用规定左边界。

时间复杂度:O(1)

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        l = 0
        r = -1
        dict1 = {}
        res = 0
        while r < len(s) - 1:
            if dict1.get(s[r + 1], 0) == 0:
                r += 1
                dict1[s[r]] = 1
            else:
                dict1[s[l]] -= 1
                l += 1
            res = max(res, r-l+1)
        return res

leetcode:125. 验证回文串

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

解法:双指针,str.isalnum() 方法-检测字符串是否由字母和数字组成。str.upper() 方法-字符串中的小写字母转为大写字母。

时间复杂度:O(n)

# 法一:双指针
class Solution:
    def isPalindrome(self, s: str) -> bool:
        s = [i for i in s.upper() if i.isalnum()]
        l = 0
        r = len(s) - 1
        while l < r:
            if s[l] != s[r]:
                return False
            else:
                l += 1
                r -= 1
        return True


# 法二:直接比较字母翻转的字符串
class Solution:
    def isPalindrome(self, s: str) -> bool:
        s = [i for i in s.upper() if i.isalnum()] 
        return s == s[::-1]

剑指offer:替换空格

问题描述:请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

解法:

1.先遍历一遍字符串,统计空格的总数。新的长度=原长度+空格数×2,准备两个指针,一个指向原始末尾,一个指向替换后的末尾,从后往前复制。

2.创建一个数组,先遍历一遍字符串,将元素分别放入数组,空格则放入替换字符,最后数组转为字符串 ''.join(a)

时间复杂度:O(n)

# -*- coding:utf-8 -*-
class Solution:
    def replaceSpace(self, s):
        # 字符串是不可变对象,不要用下标的方法去改变字符串的值
        a = []
        for i in range(len(s)):
            if s[i] == ' ':
                a.append('%20')
            else:
                a.append(s[i])
        return ''.join(a)

leetcode:14. 最长公共前缀

问题描述:编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""

解法:

1. 把数组的第一位字符串看做标准位数循环遍历(pos),从第二位字符串开始循环遍历(_),如果扫描到的字符串长度小于等于当前位数,则标志为False;如果扫描的字符串位置不等于标准位置,则标志为False

2. zip(*strs)函数将列表变换成元组。然后使用集合set的互异性,判断set后的元组长度等于1,等于1则认为该字符是公共前缀,加入公共前缀字符串

时间复杂度:

# method 1
class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        res = ''
        flag = True
        # pos : 位数
        # _ : 第几个数
        if strs == []:
            return res
        for pos in range(len(strs[0])):
            for _ in range(1, len(strs)):
                if len(strs[_]) <= pos:
                    flag = False
                elif strs[0][pos] != strs[_][pos]:
                    flag = False
            if flag:
                res += strs[0][pos]
            else:
                break
        return res


# method 2
class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        res = ""
        if len(strs) == 0:
            return ""
        # zip(*strs)函数的作用是将列表变换成元组
        for each in zip(*strs):
            # 集合set的互异性,set后的元组长度等于1则认为该字符是公共前缀,加入公共前缀字符串
            if len(set(each)) == 1:
                res += each[0]
            else:
                return res
        return res

企业真题:在串”aaabbaa”中,S的子串为S中任意连续的一段。度度熊想找的子串有”a”,”aa”,”aaa”,”b”,”bb”五种,输出子串数目。

解法:两个指针,右边界扩张,左边界识别相同元素。

import sys

line = sys.stdin.readline().strip()
l = 0
r = -1
res  = []
while r < len(line) - 1:
    if line[l] == line[r+1]:
        r += 1
    else:
        l += 1
    if line[l:r + 1] not in res and r >= l:
        res.append(line[l:r+1])
print(len(res))

leetcode:424. 替换后的最长重复字符

问题描述:给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 次。在执行上述操作后,找到包含重复字母的最长子串的长度。

解法:用字典保存字母出现的次数,需要替换的字符数目=窗口字符数目-数量最多的字符数目

时间复杂度:O(n)

class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        # 用字典保存字母出现的次数,需要替换的字符数目=窗口字符数目-数量最多的字符数目
        letter_num = {}
        l = 0
        res = 0
        for r in range(len(s)):
            # 字典保存字符出现的次数
            letter_num[s[r]] = letter_num.get(s[r], 0) + 1
            # 找到出现次数最多的字符
            max_letter = max(letter_num, key=letter_num.get)
            # 如果替换的字符数目超过给定的k,则移动左边界
            while r - l + 1 - letter_num[max_letter] > k:
                letter_num[s[l]] -= 1
                l += 1
                # 需要更新最多个数的字符
                max_letter = max(letter_num, key=letter_num.get)
            # 如果s[r] 超出了替换的字符数目,需要先处理,再计算结果
            res = max(res, r - l + 1)
            
        return res

剑指offer:字符串的排列

问题描述:输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba

解法:分别把第一个字符与其后的所有字符依次做交换,然后固定第一个字符,递归地求后面字符的排列

时间复杂度:O(n*n)

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.res = []

    def Permutation(self, ss):
        if not ss:
            return []
        # python 不可直接修改string,转换为数组进行处理
        self.Permutation_s(list(ss), 0)
        # 去重
        res = list(set(self.res))
        # 排序
        res.sort()
        return res

    def Permutation_s(self, char, start):
        # 递归到最后一位字符
        if start == len(char):
            self.res.append(''.join(char))
        # 首位start依次与其后的字符交换位置
        for i in range(start, len(char)):
            char[start], char[i] = char[i], char[start]
            # 固定首位,递归余下的字符
            self.Permutation_s(char, start + 1)
            # 复原之前的顺序
            char[start], char[i] = char[i], char[start]

剑指offer:第一个只出现一次的字符

问题描述:在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).

解法:建立一个哈希表(字典)

时间复杂度:O(n)

# -*- coding:utf-8 -*-
class Solution:
    def FirstNotRepeatingChar(self, s):
        if not s:
            return -1
        dict1 = {}
        for i in s:
            dict1[i] = dict1.get(i, 0) + 1

        for i in range(len(s)):
            if dict1[s[i]] == 1:
                return i

剑指offer:

问题描述:

解法:

时间复杂度:

发布了93 篇原创文章 · 获赞 119 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_18310041/article/details/95196799