day 5: 字符串

1. 剑指 Offer 38. 字符串的排列

输入一个字符串,打印出该字符串中字符的所有排列。

你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。

示例:

输入:s = "abc"
输出:["abc","acb","bac","bca","cab","cba"]

解法1. 递归

class Solution:
    def permutation(self, s: str) -> List[str]: 
        # # 字符串的全排列   
        result = []
        def perm(s_dir, one = ''):
            if s_dir:  
                buff = []  # 遍历所有字符,不处理 相同字符。 
                for i, x in enumerate(s_dir):
                    if x not in buff:
                        perm(s_dir[:i] + s_dir[i+1:], one+x)
                        buff.append(x)
            else:  # 找到最后, 相当于 叶子节点
                # if one not in result:  # 如果在这里判断,会超时
                result.append(one)
            return 
        perm(s)
        return result

2.  剑指 Offer 45. 把数组排成最小的数

输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。

示例 1:

输入: [10,2]
输出: "102"

示例 2:

输入: [3,30,34,5,9]
输出:"3033459"提示:

0 < nums.length <= 100
说明:

输出结果可能非常大,所以你需要返回一个字符串而不是整数
拼接起来的数字可能会有前导 0,最后结果不需要去掉前导 0

解法1:  快速排序

class Solution:
    def minNumber(self, nums: List[int]) -> str:
        # 本质上是个 排序 
        # 排序规则: x+y>y+x:  y小
        #          y+x > x +y, x小
        nums_str = [str(item) for item in nums]
        def one_sort(nums, start, end):
            # 一趟排序
            i = start
            j = end
            while i < j:
                # 从右往左扫描
                while i<j and nums[i] + nums[j] < nums[j] + nums[i]: 
                    j -= 1
                if i < j:
                    nums[i], nums[j] = nums[j], nums[i]
                    i = i + 1
                # 从左往右扫描
                while i < j and nums[i] + nums[j] < nums[j] + nums[i]: # 
                    i += 1
                if i < j:
                    nums[i], nums[j] = nums[j], nums[i]
                    j = j - 1
            return i
        # 快速排序算法 
        def quick_sort(nums, start, end):
            if start < end:
                p = one_sort(nums, start, end)
                # print(nums)
                quick_sort(nums, start, p-1)
                quick_sort(nums, p+1, end)
                
        quick_sort(nums_str, 0, len(nums_str)-1)

        return ''.join(nums_str)

3. 139. 单词拆分

给定一个非空字符串 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

解法1: 动态规划

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        # 从s出发考虑, s中字符 划分后 是否都出现在wordDict
        # 采用 动态规划(不太熟练),遍历字符串;  很巧妙; 从字典开始匹配 递归超时
        dp = [0]*(len(s)+1) 
        dp[0] = 1
        for i in range(1, len(s)+1):
            for j in range(i):
                if dp[j] == 1 and s[j:i] in wordDict:
                    dp[i] = 1   # 从i 可以开始新的匹配了
                    break
        return dp[i] == 1

4. 140. 单词拆分 II

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

说明:

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

示例:

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

 解法1:  递归 (超时)+ 投机取巧

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> List[str]:
        wordDict = sorted(wordDict)
        # any(): 可迭代对象中 若全为Fasle, 则返回False, 否则True;
        # all(): 可迭代对象中 若全为True,  则返回True, 否则Flase
        # 若想 句子中所有单词都在词典中, 句子中的 字母 必须都在 词典中出现的字符中;
        # 若 出现词典中 没出现过字符,则 必定不能组成句子; 
        if any([i not in set("".join(wordDict)) for i in s]):  # 全为False,any 返回false 
            return []   # 通过有点 投机取巧了;
        # 递归 超时 
        result = []
        def digui(s, wordDict, ju=''):
            if not s:
                result.append(ju.strip())
            for item in wordDict:
                item_len = len(item)
                if s[0:0+item_len] == item:  # 匹配成功
                    digui(s[0+item_len:], wordDict, ju + ' ' + item)
            return 
        digui(s, wordDict)
        return result

此题有个测试用例 很恶心:(去掉句子中b 依然超时)

"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
["a","aa","aaa","aaaa","aaaaa","aaaaaa","aaaaaaa","aaaaaaaa","aaaaaaaaa","aaaaaaaaaa"]

解法2:  从单词的角度去遍历, 也是投机取巧

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> List[str]:
        dp = [0]*(len(s)+1) 
        dp[0] = 1
        s_len = len(s)
        if not all([item in set(''.join(wordDict))    for item in s]):
            return []
        # 递归
        result = []
        def digui(s, wordDict, ss=''):  # 
            if not s:
                result.append(ss.strip())
            s_len = len(s)
            start = 0
            for i in range(s_len + 1):
                if s[start: start+i] in wordDict:
                    digui(s[start+i:], wordDict, ss + ' ' + s[start: start+i])
            return 
        digui(s, wordDict, '')
        return result

5. 20. 有效的括号

给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

示例 1:

输入: "()"
输出: true

示例 2:

输入: "()[]{}"
输出: true

 解法1 :

class Solution:
    def isValid(self, s: str) -> bool:
        if not s:
            return True
        qu_dict = {'(': ')', ')':'(', '{':'}', '}': '{', '[':']', ']':'['}
        # 括号匹配, 先进后出, 后入先出
        result = []
        for item in s:
            if item in [')', '}', ']'] and qu_dict[item] in result:
                # 可以进去, 是否消除
                if len(result) > 0 and result[-1] == qu_dict[item]:
                    result.pop()
                else:
                    result.append(item)
            elif item in ['(', '{', '[']:  # 直接进 不消除
                result.append(item)
            else: 
                return False
        if result:
            return False
        return True

解法2: 大神的奇思妙想,  直接替换

class Solution:
    def isValid(self, s: str) -> bool:
        while '()' in s or '[]' in s or '{}' in s:
            s = s.replace('()', '')
            s = s.replace('[]', '')
            s = s.replace('{}', '')
        if s:
            return False
        return True

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

剑指 Offer 48. 最长不含重复字符的子字符串

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

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 3:

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

解法1: 自创, 思路后续补

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        max_length = 0
        zichuan = []
        for item in s:
            zichuan.append(item)
            if item in zichuan[:-1]:
                item_index = zichuan.index(item)
                zichuan = zichuan[item_index+1:] # 去掉前面重复的

            max_length = max(max_length, len(zichuan))
        return max_length

解法2: 官方 滑动窗口

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # 官方解法 滑动窗口, 找 从头开始, 以每个字符开始 对应的 最长子串(没有重复字符), 比较长度 找到最大的;
        
        s_len = len(s)
        nk, max_len = -1, 0  # nk表示滑动窗口右侧,-1表示还没移动
        sets = set() # 哈希表, 判断是否 重复字符
        for i in range(s_len):
            if i != 0:
                sets.remove(s[i-1])  # 开始指针下移一步
            while nk+1 < s_len and s[nk+1] not in sets:
                sets.add(s[nk+1])
                nk = nk + 1
            # 出现重复的值了, 就是 i~nk 没有重复字符的 最长字串
            max_len = max(max_len, nk-i+1) 
        return max_len

7. 394. 字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

示例 1:

输入:s = "3[a]2[bc]"
输出:"aaabcbc"

解法1: 

class Solution:
    def decodeString(self, s: str) -> str:
        ### 简单在 所有数字 只表示重复次数k, 数字只表示重复;
        res = []
        for item in s:
            if item == "]": # 遇到"]" 回溯
                ress = ""
                while res and res[-1] != '[': # 方括号内部字母
                    ress = res.pop()+ress
                res.pop() # 输出[
                # 得到方括号前的数字
                nums = ""
                while res and res[-1].isdigit():
                    nums = res.pop()+nums
                if nums:
                    res.append(int(nums) * ress)
                else:
                    res.append(ress)
            else:
                res.append(item)
        # print(res)
        return "".join(res)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值