Leetcode题解 0011期

0030题 与所有单词相关联的字串【Substring with Concatenation of All Words】

题目:
给定一个字符串 s 和一些长度相同的单词 words。在 s 中找出可以恰好串联 words 中所有单词的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。

示例:

输入:
  s = "barfoothefoobarman",
  words = ["foo","bar"]
输出: [0,9]
解释: 从索引 09 开始的子串分别是 "barfoo""foobar" 。
输出的顺序不重要, [9,0] 也是有效答案。

题目不严谨之处:
1. words应该是不会有空字符串出现的,结果输入数据仍然有
2. 题目的解释中多了一个‘r’,在本博客中已经修改并删掉
3. 题目中说到words中的单词长度应该是统一的,示例2的words无法满足题目条件,在本博客中已经修改并删掉。

需要注意:
1. 不知道示例2是怎么回事,如果出现不统一长的wordsList,那么应该直接反馈空List
2. 没有说明words中不允许出现相同的单词,所以仍然需要注意
3. Robust

解题思路:
一开始没有想到特别好的思路,尝试暴力搜索,代码如下:

class Solution:
    def __init__(self):
        self.wordsList = {}

    def search(self, s, start, end, l):
        tmp = self.wordsList.copy()
        for i in range(start, end, l):
            local = s[i:i+l]
            if tmp.get(local):
                if tmp[local] > 1:
                    tmp[local] -= 1
                else:
                    del(tmp[local])
                    if len(tmp) == 0:
                        return True
            else:
                return False

    def findSubstring(self, s, words):
        if len(s) == 0 or len(words) == 0: return []
        l = len(words[0])
        cnt = len(words)
        res = []

        for word in words:
            if self.wordsList.get(word):
                self.wordsList[word] += 1
            else:
                self.wordsList[word] = 1

        for i in range(0, len(s)):
            if self.search(s, i, i+cnt*l, l):
                res.append(i)

        return res

emm,然后这段代码打进去之后,竟然才爆了两个点,点进去一看那个数据……立即加一下针对样例的“优化”

if len(self.wordsList) == 1 and self.wordsList.get('a'):
            for i in range(0, len(s)-cnt+1):
                res.append(i)
            return res

其实看了一波提交的答案,发现也都大同小异……之前也说过追求绝对速度是不可取的,所以这里也直接不管了,理论上来讲这道题一定有一些比较好的数据结构可以处理,但是没有编,然后看了一下解答也并没有,所以如果有那位大佬哪天突然有兴致想编的话,可以在下面评论。


0032题 最长有效括号【Longest Valid Parentheses】

题目:
给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。

示例:

输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"

输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"

题目相对严谨

除了Robust以外,无需注意太多

解题思路:
1.题目越短的题目,难度往往都略高一些,因为没有办法从题目中获取更多的信息,自初中正式面对考试时,这种规律就没有变过。这道题也是,看似非常容易理解的题目,但是想起来确实费一番功夫。
这题暴力搜索复杂度应该是 O ( n 3 ) ,粗略估计了一下,不过肯定不能使用了,然后觉得括号匹配的题还是用栈来实现,就简单编了一个短代码,如下:

class Solution:
    def longestValidParentheses(self, s):
        res = 0
        tmp_valid = 0
        p = list()
        for i in range(len(s)):
            if s[i] == '(':
                p.append(s[i])
            else:
                if len(p) == 0:
                    res = max(res, tmp_valid)
                    tmp_valid = 0
                elif p[-1] == '(':
                    tmp_valid += 2
                    p.pop()

        res = max(res, tmp_valid)
        return res

不过很明显这个是错误的代码,错误样例如“()(()”,想到这种错误样例,立马意识到是因为这段代码过于早的pop并计算了当下可能最长长度,所以应该在既保留当下可能最长长度,又应该一直维持并没有匹配的左括号,这里就要注意新的两个样例:“()((()”,“()((())”

class Solution:
    def longestValidParentheses(self, s):
        res = 0
        p = list()
        for i in range(len(s)):
            if s[i] == '(':
                p.append(s[i])
            else:
                if len(p) == 0: continue
                if p[-1] == '(':
                    if len(p) == 1:
                        p.pop()
                        p.append(str(2))
                    else:
                        tmp = 2
                        p.pop()
                        while len(p) > 0 and p[-1].isdigit(): tmp += int(p.pop())
                        p.append(str(tmp))
                elif p[-1].isdigit():
                    if len(p) == 1:
                        res = max(res, int(p[-1]))
                        p = list()
                    else:
                        tmp = int(p.pop()) + 2
                        p.pop()
                        while len(p) > 0 and p[-1].isdigit(): tmp += int(p.pop())
                        p.append(str(tmp))

        for c in p:
            if c.isdigit():
                res = max(res, int(c))

        return res

2.这样做无非是在不动脑子的模拟操作,这道题的提示中有着动态规划四个字,思来想去,觉得如果是DP的话,更新点肯定是在右括号,那就是字符串中有什么规律可循,参考网上的解答贴:https://blog.csdn.net/accepthjp/article/details/52439449,才发现如下规律:

dp[i]表示以当前位置为终点的最长长度,则只能在)处更新,
如果s[i-1-dp[i-1]]==’(‘,则说明当前位置可以和i-1-dp[i-1]位置匹配,dp[i]=dp[i-1]+2
然后还要加上匹配位置之前的最长长度dp[i]+=dp[i-dp[i]]

自己在草稿纸上演算了一下,还真是这个道理,有点自叹不如……附上最后的代码:

class Solution:
    def longestValidParentheses(self, s):
        max_len = 0
        dp = [-1]
        for i in range(len(s)):
            if s[i] == '(':
                dp.append(i)
            else:
                dp.pop()
                if(len(dp) == 0):
                    dp.append(i)
                else:
                    max_len = max(max_len, i - dp[-1])

        return max_len

0036题 有效的数独【Valid Sudoku】

题目:
判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
    这是一个部分填充的有效的数独。

数独部分空格内已填入了数字,空白格用 ‘.’ 表示。

说明:

  • 一个有效的数独(部分已被填充)不一定是可解的。
  • 只需要根据以上规则,验证已经填入的数字是否有效即可。
  • 给定数独序列只包含数字 1-9 和字符 ‘.’ 。
  • 给定数独永远是 9x9 形式的。

示例:

输入:
[
  ["5","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
输出: true

输入:
[
  ["8","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
输出: false
解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。
     但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。

题目相对严谨

无需注意太多

解题思路:
【密恐症人慎入的几道题(棒读)】
这题仅仅是判断数独是否有效,而并不是判断数独可否有解,所以工作量顿时降低。
简单模拟题目就好,这里不放上那么冗余的代码了。


0037题 解数独【Sudoku Solver】

题目:
编写一个程序,通过已填充的空格来解决数独问题。

一个数独的解法需遵循如下规则:

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

说明:

  • 一个有效的数独(部分已被填充)不一定是可解的。
  • 只需要根据以上规则,验证已经填入的数字是否有效即可。
  • 给定数独序列只包含数字 1-9 和字符 ‘.’ 。
  • 给定数独永远是 9x9 形式的。

空白格用 ‘.’ 表示。
这是一个数独
答案是红色的部分

题目相对严谨

经典题目无需注意太多

解题思路:
这是所有搜索题目的经典题,DFS或者BFS都可以解,然后就想到当年看到解数独时候的Dancing Links……舞蹈链算法并不是在这里用的,会爆炸。

因为是经典回溯搜索题目,所以就不post代码了。


0038题 报数【Count and Say】

题目:
报数序列是指一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:

1.     1
2.     11
3.     21
4.     1211
5.     111221

1 被读作 “one 1” (“一个一”) , 即 11。
11 被读作 “two 1s” (“两个一”), 即 21。
21 被读作 “one 2”, “one 1” (”一个二” , “一个一”) , 即 1211。

给定一个正整数 n ,输出报数序列的第 n 项。

注意:整数顺序将表示为一个字符串。

示例:

输入: 1
输出: "1"

输入: 4
输出: "1211"

题目相对严谨

除Robust以外,无需注意太多。

解题思路:
emmm,一开始看题感觉有点懵,不知道在说什么,后来想想无非还是模拟题。
post代码:

class Solution:
    def nxt(self, s):
        ss = ""
        n = len(s)
        i = 0
        while i < n:
            tmp = i + 1
            while tmp < n and s[tmp] == s[i]: tmp += 1
            ss += str(tmp - i) + s[i]
            i = tmp

        return ss

    def countAndSay(self, n):
        res = ['1']
        for i in range(1, n):
            res.append(self.nxt(res[-1]))

        return res[-1]

如果有数学解法的话,欢迎评论……


0039题 组合总和【Combination Sum】

题目:
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:

  • 所有数字(包括 target)都是正整数。
  • 解集不能包含重复的组合。

示例:

输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
  [7],
  [2,2,3]
]

输入: candidates = [2,3,5], target = 8,
所求解集为:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
] 

题目相对严谨

除Robust以外无需注意太多

解题思路:
好吧,这是一道再经典不过的回溯题目了,直接AC掉,无需post代码

猜你喜欢

转载自blog.csdn.net/bright_silmarillion/article/details/80641550