字符串--Leetcode (python)

单词拆分

给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。

说明:

拆分时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。
示例 1:

输入: s = “leetcode”, wordDict = [“leet”, “code”]
输出: true
解释: 返回 true 因为 “leetcode” 可以被拆分成 “leet code”。
示例 2:

输入: s = “applepenapple”, wordDict = [“apple”, “pen”]
输出: true
解释: 返回 true 因为 “applepenapple” 可以被拆分成 “apple pen apple”。
注意你可以重复使用字典中的单词。
示例 3:

输入: s = “catsandog”, wordDict = [“cats”, “dog”, “sand”, “and”, “cat”]
输出: false

动态规划的思路。(递归会超时)
将问题拆分成更小的子问题。用dp[i]表示0到i的子字符串是否可以拆分成满足条件的单词,在计算dp[i]的时候,只需要判断dp[i-len(word)]是否是true,如果是,那么dp[i]就是true。

class Solution(object):
    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: bool
        """
        
        len_s = len(s)
        dp = [False for i in range(len_s+1)]
        dp[0] = True
        
        for i in range(1, len_s+1):
            for word in wordDict:
                if i>=len(word) and dp[i-len(word)] and word == s[i-len(word):i]:
                    dp[i] = True
                    
        return dp[-1]

单词拆分 II

给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中。返回所有这些可能的句子。

说明:

分隔时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。

示例 1:

输入:
s = "catsanddog"
wordDict = ["cat", "cats", "and", "sand", "dog"]
输出:
[
  "cats and dog",
  "cat sand dog"
]

示例 2:

输入:
s = "pineapplepenapple"
wordDict = ["apple", "pen", "applepen", "pine", "pineapple"]
输出:
[
  "pine apple pen apple",
  "pineapple pen apple",
  "pine applepen apple"
]
解释: 注意你可以重复使用字典中的单词。

示例 3:

输入:
s = "catsandog"
wordDict = ["cats", "dog", "sand", "and", "cat"]
输出:
[]

解法:这次只能用递归,不能用动态规划了;
遍历wordDict中的每一个word,查看字符串s是否是由word开头的,即word是否是s的前缀;
若是,就将改word存储在结果中,并将s去掉这个word前缀,再进行第1步;
因为会出现很多重复搜索的过程,可以利用字典memo来保存,{’sanddog’:[‘sand dog’, ‘s and dog’]},遇到已经出现过的情况,直接查字典即可,速度会快很多。

class Solution(object):
    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: List[str]
        """
        
        def dfs(s, wordDict, memo):
            if s in memo:
                return memo[s]
            if not s:
                return []
            
            res = []
            for word in wordDict:
                if s[:len(word)] != word:
                    continue
                if len(s) == len(word):
                    res.append(word)
                else:
                    rest=dfs(s[len(word):], wordDict, memo)
                    for item in rest:
                        item = word + ' ' + item
                        res.append(item)
                        
            memo[s]=res
            return res
        
        return dfs(s,wordDict,{})
                

有效的字母异位词

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

示例 1:

输入: s = “anagram”, t = “nagaram”
输出: true
示例 2:

输入: s = “rat”, t = “car”
输出: false
说明:
你可以假设字符串只包含小写字母。

进阶:
如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?

解法:
字母异位词指字母相同,但排列不同的字符串。
两种方案:第一个是使用字典存储s中每个字母的个数,再去判断t中字母个数是否相同即可;
第二个是直接将两个字符串排序后看是否相同,非常简单

class Solution(object):
    def isAnagram(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: bool
        """
        
        return sorted(s) == sorted(t)
        

字母异位词分组

给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。

示例:

输入: [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”],
输出:
[
[“ate”,“eat”,“tea”],
[“nat”,“tan”],
[“bat”]
]
说明:

所有输入均为小写字母。
不考虑答案输出的顺序。

解法
同上,还是两种方案;
灵活使用tuple, dict等结构

class Solution(object):
    def groupAnagrams(self, strs):
        ans = collections.defaultdict(list)
        for s in strs:
            ans[tuple(sorted(s))].append(s)
        return ans.values()
class Solution:
    def groupAnagrams(strs):
        ans = collections.defaultdict(list)
        for s in strs:
            count = [0] * 26
            for c in s:
                count[ord(c) - ord('a')] += 1
            ans[tuple(count)].append(s)
        return ans.values()

字符串中的第一个唯一字符

给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。

案例:

s = “leetcode”
返回 0.

s = “loveleetcode”,
返回 2.

注意事项:您可以假定该字符串只包含小写字母。

解法
比较简单的题目,考察字典的应用。O(2n)比O(n)好得多;
记一下collections.Counter(s)的方法

本来以为会有优雅点的解法,但发现就是直接哈希。第一遍哈希得到字符次数,第二遍找到第一个位置

class Solution(object):
    def firstUniqChar(self, s):
        """
        :type s: str
        :rtype: int
        """
        
        cnt = collections.Counter(s)
        for i in range(len(s)):
            tmp = s[i]
            if cnt[tmp] == 1:
                return i
            
        return -1
# -*- coding:utf-8 -*-
class Solution:
    def FirstNotRepeatingChar(self, s):
        # write code here
        dic = {}
        for x in s:
            if x not in dic:
                dic[x] = 0
            dic[x] += 1
            
        for i in range(len(s)):
            if dic[s[i]] == 1:
                return i
            
        return -1

反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。

示例 1:

输入:[“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]
示例 2:

输入:[“H”,“a”,“n”,“n”,“a”,“h”]
输出:[“h”,“a”,“n”,“n”,“a”,“H”]

解法:

  • 比较简单,因为是O(1)的,所以想到就是前后交换,直到中间即可
  • 采用异或的形式
class Solution(object):
    def reverseString(self, s):
        """
        :type s: List[str]
        :rtype: None Do not return anything, modify s in-place instead.
        """
        ll = len(s)
        for i in range(ll/2):
            s[i], s[ll-1-i] = s[ll-1-i], s[i]
def reverseStr(s):
    if not s:
        return s
    ch = list(s)
    i , j = 0 , len(s)-1
    while i < j:
        ch[i] = chr(ord(ch[i]) ^ ord(ch[j]))
        ch[j] = chr(ord(ch[i]) ^ ord(ch[j]))
        ch[i] = chr(ord(ch[i]) ^ ord(ch[j]))
        # ch[i] = ch[i] ^ ch[j]  【错误的形式】
        # ch[j] = ch[i] ^ ch[j]
        # ch[i] = ch[i] ^ ch[j]
        i += 1
        j -= 1
    return "".join(ch)

s = 'abcdef'
print(reverseStr(s))

翻转单词

给定一个字符类型的数组chas,请在单词间做逆序调整,只要做到单词顺序逆序即可,对空格的位置没有特别要求。例如把chas看成字符串为“I love you”,调整成“you love I”。

解法
首先对整个数组逆序,然后遍历数组找到每一个单词,将每个单词里的字符进行逆序即可。

#反转字符串
def reverseStr(s):
    if not s:
        return s
    ch = list(s)
    i , j = 0 , len(s)-1
    while i < j:
        ch[i] = chr(ord(ch[i]) ^ ord(ch[j]))
        ch[j] = chr(ord(ch[i]) ^ ord(ch[j]))
        ch[i] = chr(ord(ch[i]) ^ ord(ch[j]))
        i += 1
        j -= 1
    return "".join(ch)

#s = 'abcdef'
#print(reverseStr(s))

#将句子反转,单词不反转。
def reverseWord(s):
    if not s:
        return s
    rs = reverseStr(s)
    arr = rs.split(' ')
    res = []
    for a in arr:
        res.append(reverseStr(a))
    return ' '.join(res)

s = 'I love dogs'
print(reverseWord(s))

验证回文串

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

说明:本题中,我们将空字符串定义为有效的回文串。

示例 1:

输入: “A man, a plan, a canal: Panama”
输出: true
示例 2:

输入: “race a car”
输出: false

解法

  • 用python自带的filter来做
  • 双指针法
class Solution:
    def isPalindrome(self, s: str) -> bool:
        s = list(filter(str.isalnum, s.lower()))
        return True if s == s[::-1] else False
        
class Solution:
    def isPalindrome(self, s):
        """
        :type s: str
        :rtype: bool
        """
        
        n = len(s)
        i = 0
        j = n-1

        while i < j:
            if s[i].isalnum() == False:
                i += 1
                continue
            if s[j].isalnum() == False:
                j -= 1
                continue
            if s[i].lower() != s[j].lower():
                return False
            i += 1
            j -= 1
        return True

反转字符串中的元音字母

编写一个函数,以字符串作为输入,反转该字符串中的元音字母。

示例 1:

输入: “hello”
输出: “holle”
示例 2:

输入: “leetcode”
输出: “leotcede”

解法
同样双指针方法

class Solution(object):
    def reverseVowels(self, s):
        """
        :type s: str
        :rtype: str
        """
        letters = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']
        s2 = [x for x in s]
        l, r = 0, len(s2) - 1
        while l < r:
            while l < r and s2[l] not in letters:
                l += 1
            while l < r and s2[r] not in letters:
                r -= 1
                
            s2[l], s2[r] = s2[r], s2[l]
            l += 1
            r -= 1
            
        return ''.join(s2)
        

神奇的数字

题目描述
在这个特殊的假期里,由于牛牛在家特别无聊,于是他发明了一个小游戏,游戏规则为:将字符串数字中为偶数位的数字进行翻转,将翻转后的结果进行输出。

示例1
输入
“1234”
输出
“1432”
说明
第2、4位为偶数,所以将其翻转后,得到 1432

示例2
输入
“12346”
输出
“16342”
说明
第2、4、5位为偶数,所以将其翻转后,得到 16342

备注:
数字的长度<=10^7 且不包含数字0

解法
就是个双指针,一个从左往右,一个从右往左,遇到偶数就交换一下。

#
# 
# @param number string字符串 
# @return string字符串
#
class Solution:
    def change(self , number ):
        # write code here
        if not number or len(number) == 1:
            return number
        nums = [int(x) for x in number]
        i, j = 0, len(nums) - 1
        while i < j:
            while i < j and nums[i] % 2 == 1:
                i += 1
            while i < j and nums[j] % 2 == 1:
                j -= 1
            
            nums[i], nums[j] = nums[j], nums[i]
            i += 1
            j -= 1
            
        nums = [str(x) for x in nums]
        return ''.join(nums)

字符串距离计算

题目描述
给定两个长度相等的,由小写字母组成的字符串S1和S2,定义S1和S2的距离为两个字符串有多少个位置上的字母不相等。
现在牛牛可以选定两个字母X1和X2,将S1中的所有字母X1均替换成X2。(X1和X2可以相同)
牛牛希望知道执行一次替换之后,两个字符串的距离最少为多少。

示例1
输入
“aaa”,“bbb”
输出
0
说明
牛牛可以将S1中的字符’a’全部替换成字符’b’,这样S1就变成了"bbb",那么S1和S2的距离就是0

示例2
输入
“aabb”,“cdef”
输出
3
说明
一种可行的方案是将S1中的字符’a’全部替换成字符’c’,那么S1变成了"ccbb",和S2的距离是3

备注:
在这里插入图片描述
解法
参考标准题解:
对于所有可能的X1, X2, 记录cnt[X1][X2]有多少个位置i, 使得S1[i] == X1, S2[i] == X2
这一步只需扫描一遍字符串即可计算得到
然后枚举可能的X1, X2,这时距离 = 原本的距离 + cnt[X1][X1] - cnt[X1][X2]
时间复杂度O(N)

#
# 计算最少的距离
# @param S1 string字符串 第一个字符串
# @param S2 string字符串 第二个字符串
# @return int整型
#
class Solution:
    def GetMinDistance(self , S1 , S2 ):
        # write code here
        cnt = [[0 for i in range(26)] for j in range(26)]
        
        ans = 0
        for i in range(len(S1)):
            x, y = S1[i], S2[i]
            xx, yy = ord(x) - ord('a'), ord(y) - ord('a')
            cnt[xx][yy] += 1
            if xx != yy:
                ans += 1
        
        res = ans
        for i in range(26):
            for j in range(26):
                res = min(res, ans + cnt[i][i] - cnt[i][j])
                
        return res
    

安置路灯

题目描述
小Q正在给一条长度为n的道路设计路灯安置方案。

为了让问题更简单,小Q把道路视为n个方格,需要照亮的地方用’.'表示, 不需要照亮的障碍物格子用’X’表示。

小Q现在要在道路上设置一些路灯, 对于安置在pos位置的路灯, 这盏路灯可以照亮pos - 1, pos, pos + 1这三个位置。

小Q希望能安置尽量少的路灯照亮所有’.'区域, 希望你能帮他计算一下最少需要多少盏路灯。

输入描述:
输入的第一行包含一个正整数t(1 <= t <= 1000), 表示测试用例数
接下来每两行一个测试数据, 第一行一个正整数n(1 <= n <= 1000),表示道路的长度。
第二行一个字符串s表示道路的构造,只包含’.‘和’X’。
输出描述:
对于每个测试用例, 输出一个正整数表示最少需要多少盏路灯。

示例1
输入
2
3
.X.
11
…XX…XX

输出
1
3

解法
比较简单的贪心算法,判断好边界条件即可


t = int(input().strip())
for _ in range(t):
    n = int(input().strip())
    s = input().strip()
    res = 0
    flag = 0
    for i in range(n):
        if flag == 0 and s[i] == '.':
            if i == n - 1:
                res += 1
            else:
                flag = 1
        elif flag == 1:
            res += 1
            flag = 2
        elif flag == 2:
            flag = 0
            
    print(res)

最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 “”。

示例 1:

输入: [“flower”,“flow”,“flight”]
输出: “fl”

示例 2:
输入: [“dog”,“racecar”,“car”]
输出: “”
解释: 输入不存在公共前缀。

说明:
所有输入只包含小写字母 a-z 。

解法
就是选出来一个,挨个从头到尾比较一下

class Solution(object):
    def longestCommonPrefix(self, strs):
        """
        :type strs: List[str]
        :rtype: str
        """
        if not strs:
            return ""
        res = 0
        for i in range(len(strs[0])):
            flag = 0
            char = strs[0][i]
            for j in range(1, len(strs)):
                s = strs[j]
                if i >= len(s) or s[i] != char:
                    flag = 1
                    break
            if flag == 1:
                break
            else:
                res += 1
                
        return strs[0][:res]
            

无重复字符的最长子串

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

示例 1:

输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:

输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:

输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

解法
滑动窗口的方法,用一个字典存储每个字符的最后位置,随时判断窗口左端是否在当前字符最后位置的左边,如果是,那说明出现了重复,就更新。

class Solution(object):
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        res = 0
        start = 0
        dic = {}
        for i in range(len(s)):
            if s[i] in dic and start <= dic[s[i]]:
                start = dic[s[i]] + 1
            dic[s[i]] = i
            res = max(res, i - start + 1)
            
        return res
                

同构字符串

给定两个字符串 s 和 t,判断它们是否是同构的。

如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。

所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。

示例 1:

输入: s = “egg”, t = “add”
输出: true
示例 2:

输入: s = “foo”, t = “bar”
输出: false
示例 3:

输入: s = “paper”, t = “title”
输出: true
说明:
你可以假设 s 和 t 具有相同的长度。

解法
用字典存储单词的映射关系即可。但是需要注意用两个词典,因为不管要让s映射到t,t也要能映射到s

class Solution(object):
    def isIsomorphic(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: bool
        """
        dic1, dic2 = {}, {}
        n = len(s)
        for i in range(n):
            char_s, char_t = s[i], t[i]
            if char_s not in dic1:
                dic1[char_s] = char_t
            elif dic1[char_s] != char_t:
                return False
            
            if char_t not in dic2:
                dic2[char_t] = char_s
            elif dic2[char_t] != char_s:
                return False
            
        return True

你可能感兴趣的:(leetcode,Python)