leetcode刷题记录50-100-基于python

51. N 皇后-Hard

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        self.res = []
        trans = lambda path : ['.' * i +  'Q' + '.'*(len(path) - 1 - i) for i in path]
        def recursion(n, path, pos):
            if len(path) == n:
                self.res.append(trans(path))
                return
            l, r, m = pos
            l, r = [i-1 for i in l], [i + 1 for i in r]
            total = l + r + m
            for cand in range(n):
                if  cand in total:
                    continue
                recursion(n, path + [cand], [l + [cand], r + [cand], m + [cand]])
        recursion(n, [], [[], [], []])
    	return self.res

52. N皇后 II-Hard

class Solution:
    def totalNQueens(self, n: int) -> int:
        self.res = []
        trans = lambda path : ['.' * i +  'Q' + '.'*(len(path) - 1 - i) for i in path]
        def recursion(n, path, pos):
            if len(path) == n:
                self.res.append(trans(path))
                return
            l, r, m = pos
            l, r = [i-1 for i in l], [i + 1 for i in r]
            total = l + r + m
            for cand in range(n):
                if  cand in total:
                    continue
                recursion(n, path + [cand], [l + [cand], r + [cand], m + [cand]])
        recursion(n, [], [[], [], []])
        return len(self.res)

class Solution:
    def totalNQueens(self, n: int) -> int:
        self.res = 0
        def recursion(path, pos):
            if len(path) == n:
                self.res += 1
                return
            l, r = pos
            l, r = [i-1 for i in l], [i + 1 for i in r]
            total = l + r + path
            for cand in range(n):
                if  cand in total:
                    continue
                recursion(path + [cand], [l + [cand], r + [cand]])
        for i in range(n // 2):
            recursion([i], [[i], [i]])
        self.res *= 2
        if n % 2:
            recursion([n // 2], [[n // 2], [n // 2]])
        return self.res

53. 最大子序和-Easy

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        # 若list 中所有数均小于0
        if max(nums) < 0:
            return max(nums)
        local_max, global_max = 0, 0
        for num in nums:
            local_max = max(0, local_max + num)
            global_max = max(global_max, local_max)
        return global_max

54. 螺旋矩阵-Medium

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        # matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
        # 获取行数
        row = len(matrix)
        if row == 0 or len(matrix[0]) == 0:
            return []
        # 获取列数
        col = len(matrix[0])
        # 第一行为
        res = matrix[0]
        
        if row > 1:
            # 获取最后一列 8, 12
            for i in range(1, row):
                res.append(matrix[i][col - 1])
            # 获取最后一行 11, 10 ,9
            for j in range(col - 2, -1, -1):
                res.append(matrix[row -1][j])
            if col > 1:
                # 获取5
                for i in range(row - 2, 0, -1):
                    res.append(matrix[i][0])
        # 将剩下的 6, 7 作为新list 递归进spiralOrder
        M = []
        for k in range(1, row - 1):
            t = matrix[k][1:-1]
            M.append(t)
        return res + self.spiralOrder(M)    

55. 跳跃游戏 - Medium

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        n = len(nums)
        reach = 0
        for i in range(n):
            if reach >= n - 1 or reach < i:
                break
            reach = max(reach, nums[i] + i)
        return reach >= n - 1

56. 合并区间-Medium

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        result = []
        intervals.sort(key = lambda x : x[0])
        i = 0
        while i < len(intervals):
            cur_start = intervals[i][0]
            cur_end = intervals[i][1]
            if result:
                prev_start, prev_end = result[-1]
                hi = min(prev_end, cur_end)
                lo = max(prev_start, cur_start)

                if lo <= hi:
                    if cur_end > prev_end:
                        result[-1][1] = cur_end
                else:
                    result.append(intervals[i])
            else:
                intervals.append(intervals[i])
            i += 1
        return result

class Solution:
    def merge(self, intervals):
        """
        :type intervals: List[Interval]
        :rtype: List[Interval]
        """
        if not intervals:
            return []
        intervals.sort(key=lambda x: x[0])
        pre, cur, n = 0, 1, len(intervals)
        while cur < n:
            if intervals[pre][1] < intervals[cur][0]:
                pre += 1
                intervals[pre] = intervals[cur]
            else:
                intervals[pre][1] = max(intervals[pre][1], intervals[cur][1])
            cur += 1

        return intervals[:pre+1]

57. 插入区间-Medium

class Solution:
    def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]:
        index = 0
        while(index < len(intervals) and newInterval[0] > intervals[index][0]):
            index += 1
        intervals.insert(index, newInterval)
        res = []
        last = None
        for interval in intervals:
            if not last or last[1] < interval[0]:
                res.append(interval)
                last = interval
            else:
                last[1] = max(last[1], interval[1])
        return res

58. 最后一个单词的长度-Easy

class Solution:
    def lengthOfLastWord(self, s: str) -> int:
        count = 0
        local_count = 0
        for i in range(len(s)):
            if s[i] == ' ':
                local_count = 0
            else:
                local_count += 1
                count = local_count
        return count

59. 螺旋矩阵 II-Medium

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        # 初始化结果矩阵
        matrix = []
        for i in range(n):
            matrix.append([0 for j in range(n)])
        # 初始化行,列索引和值
        rowBegin = 0
        rowEnd = n - 1
        colBegin = 0
        colEnd = n - 1
        number = 1
        
        while colBegin <= colEnd and rowBegin <= rowEnd:
            # 对第一行赋值
            for i in range(colBegin, colEnd + 1):
                matrix[rowBegin][i] = number
                number += 1
            rowBegin += 1
        
            # 对最后一列赋值
            for i in range(rowBegin, rowEnd + 1):
                matrix[i][colEnd] = number
                number += 1
            colEnd -= 1

            # 最后一行
            if rowBegin <= rowEnd:
                for i in range(colEnd, colBegin - 1, -1):
                    matrix[rowEnd][i] = number
                    number += 1
                rowEnd -= 1

            # 最后的行
            if colBegin <= colEnd:
                for i in range(rowEnd, rowBegin - 1, -1):
                    matrix[i][colBegin] = number
                    number += 1
                colBegin += 1
        return matrix

60. 排列序列-Hard

class Solution:
    def getPermutation(self, n: int, k: int) -> str:
        ans = ''
        digits = [i for i in range(1, n + 1)]
        for i in range(n -1 , -1, -1):
            curbase = math.factorial(i)
            curindex = (k - 1) // curbase
            ans += str(digits[curindex])
            digits.remove(digits[curindex])
            k = k - curindex * curbase
        return ans

61. 旋转链表-Medium

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def rotateRight(self, head: ListNode, k: int) -> ListNode:
        # 链表长度大于2才可以旋转
        if head is None or head.next is None:
            return head
        # 计算链表长度
        n = 0
        p = head
        while p:
            n += 1
            p = p.next

        # 用k对n进行取余,判断实际需要移动几次(每n次和原链表形状一致)
        k = k % n
        if k == 0:
            return head

        # 计算要移动的位置
        p1, p2 = head, head 
        for i in range(k):
            p2 = p2.next
        while p2 and p2.next:
            p1 = p1.next
            p2 = p2.next
        # 旋转链表
        output = p1.next
        p1.next = None
        p2.next = head
        return output 

62. 不同路径-Medium

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        # 初始化第一行及第一列全为1
        # 剩余格子值为该格子相邻左边、上边格子的和
        # 依次更新第二行,第三行
        if m == 0 or n == 0:
            return 1
        # 初始化时候可以将list全部初始化为1,再计算除了第一行第一列的值
        cache = [[1] * n for _ in range(m)]
        # print(cache)
        # [[1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1]]
        for i in range(1, m):
            for j in range(1, n):
                cache[i][j] = cache[i - 1][j] + cache[i][j - 1]
        return cache[-1][-1]

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        # 或者采用排列组合,先计算到达目的地需要多少次右边n和多少次向下m移动
        # 如题目中,需要进行6次右,2次下
        # C(2, 8) / C(6, 8)
        res = 1
        div = 1
        for i in range(m, m+n-1):
            res *= i
            div *= (i - m + 1)
        return res // div

63. 不同路径 II-Medium

class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
        # 初始化第一行全为1, 遇到障碍物,障碍物及右边的所有格子为0
        # 再更新第二行第一列为1
        # 第二行剩余格子值为该格子相邻左边、上边格子的和
        # 依次更新第三行
        if not obstacleGrid:
            return 0
        m, n = len(obstacleGrid), len(obstacleGrid[0])
        cache = [[0] * n for _ in range(m)]
        cache[0][0] = 1
        for i in range(m):
            for j in range(n):
                # 遇到障碍物
                if obstacleGrid[i][j] == 1:
                    cache[i][j] = 0
                else:
                    if i > 0:
                        cache[i][j] += cache[i - 1][j]
                    if j > 0:
                        cache[i][j] += cache[i][j - 1]
        return cache[-1][-1]

64. 最小路径和-Medium

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        if not grid:
            return 0
        # 采用动态规划思想
        # 初始化动态规划list, 外加一层padding
        dp = [[2**31-1 for _ in range(len(grid[0]) + 1)] for _ in range(len(grid) + 1)] 
        for i in range(1, len(grid) + 1):
            for j in range(1, len(grid[0]) + 1):
                if i == 1 and j == 1:
                    dp[i][j] = grid[i - 1][j - 1]
                    continue
                # 动态规划方程
                dp[i][j] = grid[i - 1][j - 1] + min(dp[i - 1][j], dp[i][j - 1])
        return dp[-1][-1]

65. 有效数字-Hard

这道题应该难在考虑各种情况。所有的字符可以分为六大类,空格,符号,数字,小数点,自然底数和其他字符,我们需要五个标志变量,num, dot, exp, sign分别表示数字,小数点,自然底数和符号是否出现,numAfterE表示自然底数后面是否有数字,那么我们分别来看各种情况:

- 空格: 我们需要排除的情况是,当前位置是空格而后面一位不为空格,但是之前有数字,小数点,自然底数或者符号出现时返回false。

- 符号:符号前面如果有字符的话必须是空格或者是自然底数,标记sign为true。

- 数字:标记num和numAfterE为true。

- 小数点:如果之前出现过小数点或者自然底数,返回false,否则标记dot为true。

- 自然底数:如果之前出现过自然底数或者之前从未出现过数字,返回false,否则标记exp为true,numAfterE为false。

- 其他字符:返回false。

最后返回num && numAfterE即可。
class Solution:
    def isNumber(self, s: str) -> bool:
        try:
            float(s)
            return True
        except:
            return False

class Solution(object):
    def isNumber(self, s):
        """
        :type s: str
        :rtype: bool
        """
        if not s:
            return False
        INVALID = 0
        SPACE = 1
        SIGN = 2
        DIGIT = 3
        DOT = 4
        E = 5
 
        transition = [
            [-1,0,3,1,2,-1],
            [-1,8,-1,1,4,5],
            [-1,-1,-1,4,-1,-1],
            [-1,-1,-1,1,2,-1],
            [-1,8,-1,4,-1,5],
            [-1,-1,6,7,-1,-1],
            [-1,-1,-1,7,-1,-1],
            [-1,8,-1,7,-1,-1],
            [-1,8,-1,-1,-1,-1]
        ]
 
        state = 0
        for i in s:
            if i == ' ':
                idx = SPACE
            elif i == '-' or i == '+':
                idx = SIGN
            elif i >= '0' and i <= '9':
                idx = DIGIT
            elif i == '.':
                idx = DOT
            elif i == 'E' or i == 'e':
                idx = E
            else:
                idx = INVALID
            state = transition[state][idx]
            if state == -1:
                return False
        return state == 1 or state == 4 or state == 7 or state == 8

66. 加一-Easy

class Solution:
    def plusOne(self, digits: List[int]) -> List[int]:
        if digits[-1] == 9:
            flag = 1
        else:
            flag = 0
        for i in range(len(digits)-1, -1, -1):
            if i == len(digits)-1:
                flag = 1
            if digits[i] + flag > 9:
                digits[i] = 0
                flag = 1
            else:
                digits[i] = digits[i]+flag
                flag = 0
        if flag:
            digits.insert(0,1)
        return digits

class Solution:
    def plusOne(self, digits: List[int]) -> List[int]:
        for i in reversed(range(len(digits))):
            if digits[i] == 9:
                digits = 0
            else:
                digits[i] += 1
                return digits
        # input : 9 -> output : 10
        digits[0] = 1
        digits.append(0)
        return digits

67. 二进制求和-Easy

class Solution:
    def addBinary(self, a: str, b: str) -> str:
        result, carry, val = '', 0, 0
        for i in range(max(len(a), len(b))):
            val = carry
            if i < len(a):
                val += int(a[-(i + 1)])
            if i < len(b):
                val += int(b[-(i + 1)])
            carry, val = val // 2, val % 2
            result += str(val)
        if carry:
            result += str(1)
        return result[::-1]

68. 文本左右对齐-Hard

class Solution:
    def fullJustify(self, words: List[str], maxWidth: int) -> List[str]:
        # res: 返回结果
        # line: 缓存每一行单词
        # counter: 统计当前进入line的单词总长度
        res, line, counter = [], [], 0
        for word in words:
            # 采用贪心策略,每一行尽可能多放
            if counter + len(word) + len(line) > maxWidth:
                # 一行放不下时候,另起一行
                for i in range(maxWidth - counter):
                    line[i % max(len(line) - 1, 1)] += ' '
                res.append(''.join(line))
                line, counter = [], 0
            line += [word]
            counter += len(word)
        # ljust()左对齐
        return res + [' '.join(line).ljust(maxWidth)]

69. x 的平方根-Easy

class Solution:
    def mySqrt(self, x: int) -> int:
        if x < 2:
            return x
        left, right = 1, x // 2
        while left <= right:
            mid = left + (right - left) // 2
            if mid > x / mid:
                right = mid - 1
            else:
                left = mid + 1
        return left - 1

70. 爬楼梯-Easy

class Solution:
    def climbStairs(self, n: int) -> int:
        # n = 1, 1种
        # n = 2, 2种
        # n = 3, 3种
        # ....
        # n = n , n + n - 1种
        # 斐波那契数列(结果 = 前两个结果之和)
        prev, current = 0, 1
        for i in range(n):
            prev, current = current, prev + current
        return current

71. 简化路径-Medium

class Solution:
    def simplifyPath(self, path: str) -> str:
        result = []
        path_list = path.split('/')
        for p in path_list:
            if p:
                if p == '..':
                    if result:
                        result.pop()
                elif p == '.':
                    continue
                else:
                    result.append(p)
        res = '/' + '/'.join(result)
        return res

72. 编辑距离-Hard

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        #  topens 用于堆放(word1*, word2*..)
        # visited 用于存放已见过的(word1*, word2*..)词语对
        # 用删除的方式,把已经匹配好的word1*, word2*字母删去,
        # 三种基本操作
        # word1*删去头字母
        # word2*删去头字母
        # 两词同时删去头字母
        w1, w2, opened = word1, word2, set()
        topens = [(w1, w2, 0)]
        while True:
            (w1, w2, value) = topens.pop(0)
            if (w1, w2) in opened:
                continue
            if w1 == w2:
                return value
            opened.add((w1, w2))
            while w1 and w2 and w1[0] == w2[0]:
                w1, w2 = w1[1:], w2[1:]
            value += 1
            topens += [(w1[1:], w2, value),
                        (w1, w2[1:], value),
                        (w1[1:], w2[1:], value)
            ]
        return -1

73. 矩阵置零-Medium

class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        m, n = len(matrix), len(matrix[0])
        zero_row, zero_col = False, False
        for i in range(m):
            for j in range(n):
                if matrix[i][j] == 0:
                    matrix[i][0] = matrix[0][j] = 0
                    zero_row = True if i == 0 else zero_row
                    zero_col = True if j == 0 else zero_col
        
        for j in range(1, n):
            if matrix[0][j] == 0:
                for i in range(1, m):
                    matrix[i][j] = 0
        for i in range(1, m):
            if matrix[i][0] == 0:
                for j in range(1, n):
                    matrix[i][j] = 0
                
        if zero_row:
            for j in range(n):
                matrix[0][j] = 0
            
        if zero_col:
            for i in range(m):
                matrix[i][0] = 0

        return 

74. 搜索二维矩阵-Medium

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        # 升序矩阵,采用二分法
        m, n = len(matrix), len(matrix[0])
        if m == 0:
            return False
        left = 0
        right = m * n
        while left < right:
            mid = (left + right) // 2
            i = mid // n
            j = mid % n
            if matrix[i][j] < target:
                left = mid + 1
            elif matrix[i][j] > target:
                right = mid
            else:
                return True
        return False

75. 颜色分类-Medium

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        p, q = 0, 0
        k = len(nums) - 1
        while q <= k:
            if p < q and nums[q] == 0:
                nums[p], nums[q] = nums[q], nums[p]
                p += 1
            elif nums[q] == 2:
                nums[q], nums[k] = nums[k], nums[q]
                k -= 1
            else:
                q += 1

76. 最小覆盖子串-Hard

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        # 创建一个键值对,统计每个字符出现次数
        d = dict(collections.Counter(t)) # {'A':0, 'B':1...}
        # 用于描述ABC中多少字符满足要求
        formed = 0
        # 左指针
        slow = 0
        # 记录最短长度及substring
        min_str = None
        min_length = sys.maxsize - 1
        for fast in range(len(s)):
            ch = s[fast]
            fast += 1
            if ch not in d:
                continue
            # 更新词频
            d[ch] -= 1
            if d[ch] == 0:
                formed += 1
            while formed == len(d) and slow <= fast:
                curr_length = fast - slow 
                if curr_length < min_length:
                    min_length = curr_length
                    min_str = s[slow:fast]
                # 更新左边界
                ch = s[slow]
                slow += 1
                if ch not in d:
                    continue
                d[ch] += 1
                if d[ch] == 1:
                    formed -= 1
        return min_str if min_str is not None else ''

77. 组合-Medium

class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        import itertools
        return list(itertools.combinations(range(1, n + 1), k))

class Solution:
	def combine(self, n, k):
		ans = []
		nums = [i + i for i in range(n)]
		def dfs(last, now):
			if len(now) == k:
				ans.append(now)
			for i in range(len(last)):
				dfs(last[i + 1:], now + [last[i]])
		dfs(nums, [])
	return ans

78. 子集-Medium

#方法1:递归方法,[1,2,3] --> ([1] + [2,3]子集)+[2,3]子集
class Solution:
    def subsets(self, nums) :
        res = []
        if not nums:
            return [[]]
        else:
            sub = self.subsets(nums[1:])
            res = res + sub
            for s in sub:
                res.append(nums[:1]+s)
        return res

#方法2 位运算方法:对每一位为1的表示这一位的数字存在,例如对于输入[1,2,3] 编码i=001,表示只含有3,编码i=101.表示含有1,3
class Solution:
    def subsets(self, nums):
        t=len(nums)
        res=[]
        for i in range(2**t):
            tmp=[]
            for j in range(t):
                if i&(1<<j):
                    tmp.append(nums[t-1-j])
            res.append(tmp)
        return res
 
#方法三 排列组合
class Solution:
    def subsets(self, nums):
        from itertools import combinations
        print([list(s) for s in list(combinations(nums, 2))])
        return sum([list(combinations(nums, i)) for i in range(len(nums) + 1)], [])
 
#方法四:遇到一个数添加一下
class Solution:
    def subsets(self, nums):
        res = []
        res.append([])
        for x in nums:
            new = [s+ [x] for s in res]
            res = res + new
        return res
#方法五:回溯方法 https://leetcode-cn.com/problems/subsets/solution/hui-su-jie-fa-by-jawhiow/
class Solution(object):
    def __init__(self):
        self.result_all = None
 
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        self.result_all = []
        self.dfs(nums, 0, 0, [])
        return self.result_all
 
    def dfs(self, nums, n, start, result):
        self.result_all.append(result[:])
        if len(nums) == n:
            return
 
        for i in range(start, len(nums)):
            result.append(nums[i])
            self.dfs(nums, n + 1, i + 1, result)
            result.pop()
        return

79. 单词搜索-Medium

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        for i in range(len(board)):
            for j in range(len(board[0])):
                # helper(board, i, j, word本身, word索引)
                if self.helper(board, i, j, word, 0):
                    return True
        return False

    
    def helper(self, board, i, j, word, wordIndex):
        # 说明已经找到了答案
        if wordIndex == len(word):
            return True
        # board[0, x] 或者 board[x, len(board)]等边界情况及查找结果不匹配
        if i < 0 or i >= len(board) or j < 0 or j >= len(board[0]) or word[wordIndex] != board[i][j]:
            return False
        # 避免每个字母使用多次,用特殊字母标记
        board[i][j] = '#'
        # 开始上下左右查找
        found = self.helper(board, i + 1, j, word, wordIndex + 1)\
                or self.helper(board, i, j + 1, word, wordIndex + 1)\
                or self.helper(board, i - 1, j, word, wordIndex + 1)\
                or self.helper(board, i, j - 1, word, wordIndex + 1)
        # 查找完后,复原标记
        board[i][j] = word[wordIndex]
        return found

80. 删除有序数组中的重复项 II-Medium

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        # 满足新要求的数组索引
        j = 0
        # 用于遍历索引
        i = 0
        count = 1
        while i < len(nums):
            if i < len(nums) - 1 and nums[i] == nums[i + 1]:
                count += 1
            else:
                # 插入j为末尾的新标记数组
                d = min(count, 2)
                for k in range(d):
                    nums[j] = nums[i]
                    j += 1
                # 新的起点
                count = 1
            # 下一个判断索引
            i += 1
        return len(nums[:j])

81. 搜索旋转排序数组 II-Medium

class Solution:
    def search(self, nums: List[int], target: int) -> bool:
        # num_len = len(nums)
        # if num_len == 0:
        #     return False
        # mid = num_len // 2
        # result = False
        # if nums[mid] == target:
        #     return True
        # elif num_len == 1:
        #     return target == nums[0]
        # elif target > nums[mid]:
        #     if mid > 0 and (nums[mid - 1] > nums[mid] or nums[0] > nums[mid]):
        #         result = self.search(nums[:mid], target)
        #     return result if result is True else self.search(nums[mid+1:], target)
        # else:
        #     if mid < num_len - 1 and (nums[mid] > nums[mid + 1] or nums[mid+1] > nums[-1]):
        #         result = self.search(nums[mid+1:], target)
        #     return result if result is True else self.search(nums[:mid], target)
        left = 0
        right = len(nums)-1
        while left <= right:
            mid = (left+right)//2
            if nums[mid]==target:
                return True
            if nums[mid] == nums[left] == nums[right]:
                left += 1
                right -= 1
            elif nums[mid]>=nums[left]:
                if nums[left]<=target<=nums[mid]:
                    right = mid - 1
                else:
                    left = mid + 1
            else:
                if nums[mid]<=target<=nums[right]:
                    left = mid + 1
                else:
                    right = mid - 1

        return False           

82. 删除排序链表中的重复元素 II-Medium

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        if head == None or head.next == None:
            return head
        tmp = ListNode(-1)
        slow = tmp
        fast = head
        while fast:
            if fast.next and fast.val == fast.next.val:
                ee = fast.val
                while fast and ee == fast.val:
                    fast = fast.next
            else:
                slow.next = ListNode(fast.val)
                slow = slow.next
                fast = fast.next
        return tmp.next

83. 删除排序链表中的重复元素-Easy

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        current = head
        while current:
            runner = current.next
            while runner and runner.val == current.val:
                runner = runner.next
            current.next = runner
            current = runner
        return head

84. 柱状图中最大的矩形-Hard

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        # 定义栈
        stack = []
        # 加上首尾标记处理特殊情况
        heights = [0] + heights + [0]
        res = 0
        for i in range(len(heights)):
            while stack and heights[i] < heights[stack[-1]]:
                # 找到最大栈顶元素
                top = stack.pop()
                # 该元素右侧
                r = i - 1
                # 该元素左侧
                l = stack[-1] + 1
                # 计算面积
                area = (r - l + 1) * heights[top]
                res = max(area, res)
            stack.append(i)
        return res

85. 最大矩形-Hard

class Solution:
    def maximalRectangle(self, matrix: List[List[str]]) -> int:
        res = 0
        for i, row in enumerate(matrix):
            if i == 0:
                _heights = [int(ch == '1') for ch in row]
            else:
                for j in range(len(row)):
                    if row[j] == '0':
                        _heights[j] = 0
                    else:
                        _heights[j] += 1
            stack = []
            height = [0] + _heights + [0]
            for j in range(len(height)):
                while stack and height[j] < height[stack[-1]]:
                    top = stack.pop()
                    l = stack[-1] + 1
                    r = j - 1
                    area = (r - l + 1) * height[top]
                    res = max(area, res)
                stack.append(j)
        return res

86. 分隔链表-Medium

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def partition(self, head: ListNode, x: int) -> ListNode:
        dummySmaller, dummyGreater = ListNode(-1), ListNode(-1)
        smaller, greater = dummySmaller, dummyGreater
        while head:
            if head.val < x:
                smaller.next = head
                smaller = smaller.next
            else:
                greater.next = head
                greater = greater.next
            head  = head.next
        smaller.next = dummyGreater.next
        greater.next = None
        return dummySmaller.next 

87. 扰乱字符串-Hard

class Solution:
    def isScramble(self, s1: str, s2: str) -> bool:
        if len(s1) != len(s2):
            return False
        if s1 == s2:
            return True
        if sorted(s1) != sorted(s2):
            return False

        for i in range(1, len(s1)):
            if self.isScramble(s1[:i], s2[:i]) and self.isScramble(s1[i:], s2[i:]) or \
                    (self.isScramble(s1[:i], s2[-i:]) and self.isScramble(s1[i:], s2[:-i])):
                return True
        return False

class Solution:
    def isScramble(self, s1: str, s2: str) -> bool:
        n = len(s1)
        dp = [[[False]*(n+1) for _ in range(n)] for _ in range(n)]
        for i in range(n):
            for j in range(n):
                dp[i][j][1] = s1[i]==s2[j]
        for l in range(2, n+1):
            for i in range(n-l+1):
                for j in range(n-l+1):
                    for k in range(1, l):
                        if dp[i][j][k] and dp[i+k][j+k][l-k] or \
                            dp[i][j+l-k][k] and dp[i+k][j][l-k]:
                            dp[i][j][l] = True
                            break
        return dp[0][0][n]

88. 合并两个有序数组-Easy

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        while m > 0 and n > 0:
            # 从后往前判断,找到nums1和nums2中最大的数放在末尾
            if nums1[m-1] < nums2[n-1]:
                nums1[m-1+n] = nums2[n-1]
                # 已经放入一个数字,因此减少一位
                n = n -1
            else:
                # 如果最大数在nums1中已经排好序,与最后一个位置元素交换
                nums1[m-1+n], nums1[m-1] = nums1[m-1], nums1[m-n+1]
                m = m - 1
        # 插入后,将nums1中的0使用nums2剩下的元素替换
        if m == 0 and n > 0:
            nums1[:n] = nums2[:n]
        return nums1

89. 格雷编码-Medium

class Solution:
    def grayCode(self, n: int) -> List[int]:
        if(n==0):return [0]
        l=[0,1]
        t=2
        h=1
        while(h<n):
            e=l[::-1]
            for i in e:
                l.append(i+t)
            t=t*2
            h=h+1
        return l

90. 子集 II-Medium

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        res = [[]]
        for i in nums:
            cr = []
            for j in res:
                if j + [i] not in res:
                    cr += [j + [i]]
            res += cr          
        return res

class Solution:
    def subsetsWithDup(self, nums: 'List[int]') -> 'List[List[int]]':
        nums.sort()
        res = []
        self.dfs(nums,0,[],res)
        return res
    
    def dfs(self,nums,k,path,res):
        res.append(path)
        for i in range(k,len(nums)):
            if i > k and nums[i] == nums[i-1]:continue
            self.dfs(nums,i+1,path+[nums[i]],res)

91. 解码方法-Medium

class Solution:
    def numDecodings(self, s: str) -> int:
        from functools import lru_cache
        # 存储之前找到的结果到内存中,减少计算
        @lru_cache(None)
        def helper(n):
            if n == 0:
                return 1
            ans = 0
            if n >= 1 and s[n-1] != '0':
                ans += helper(n-1)
            if n >= 2 and 10 <= int(s[n-2:n]) <= 26:
                ans += helper(n-2)
            return ans
        return helper(len(s))

def numDecodings(self, s):
        dp = [-1 for i in range(len(s)+1)]
        dp[0] = 1
        def helper(n):
            if dp[n] != -1:
                return dp[n]
            ans = 0
            if n >= 1 and s[n-1] != '0':
                ans += helper(n-1)
            if n >= 2 and 10 <= int(s[n-2:n]) <= 26:
                ans += helper(n-2)
            dp[n] = ans
            return ans
        return helper(len(s))

    def numDecodings(self, s):
        n = len(s)
        if n == 1:
            return 1 if s[0] != '0' else 0
        prev2 = 1
        prev1 = 1 if s[0] != '0' else 0
        for i in range(2, len(s) + 1):
            cur = 0
            if s[i-1] != '0':
                cur += prev1
            if 10 <= int(s[i-2:i]) <= 26:
                cur += prev2
            prev2 = prev1
            prev1 = cur 
        return prev1

92. 反转链表 II-Medium

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
        dummy = ListNode(0)
        dummy.next = head

        before = dummy
        m = left
        n = right
        for i in range(0, m - 1):
            before = before.next
        
        start = before.next
        then = start.next

        for i in range(0, n - m):
            start.next = then.next
            then.next = before.next
            before.next = then
            then = start.next
        return dummy.next          

93. 复原 IP 地址-Medium

class Solution:
    def restoreIpAddresses(self, s: str) -> List[str]:
        res = []
        def backtrace(cnt = 0, ip = '', s = ''):
            if cnt == 4:
                if s == '':
                    res.append(ip[:-1])
                return 
            if len(s) > 0:
                backtrace(cnt + 1, ip + s[0] + '.', s[1:])
            if len(s) > 1 and s[0] != '0':
                backtrace(cnt + 1, ip + s[:2] + '.', s[2:])
            if len(s) > 2 and s[0] != '0' and int(s[0:3]) < 256:
                backtrace(cnt + 1, ip + s[:3] + '.', s[3:])

        backtrace(0, '', s)        
        return res

94. 二叉树的中序遍历-Medium

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        res = []
        def helper(root):
            if not root:
                return
            helper(root.left)
            res.append(root.val)
            helper(root.right)
        helper(root)
        return res 

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        res = []
        stack = []
        cur = root
        while cur or stack:
            while cur:
                stack.append(cur)
                cur = cur.left
            cur = stack.pop()
            res.append(cur.val)
            cur = cur.right
        return res

95. 不同的二叉搜索树 II-Medium

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def generateTrees(self, n: int) -> List[TreeNode]:
        if n == 0:
            return []
        return self.helper(1, n)


    def helper(self, start, end):
        if start > end:
            return [None]
        res = []
        # 任取一个root作为该树的root
        for cur_root in range(start, end + 1):
            # 获取左右树的结构
            left = self.helper(start, cur_root - 1)
            right = self.helper(cur_root + 1, end)
            # 对所有可能的树进行组合
            for l in left:
                for r in right:
                    root = TreeNode(cur_root)
                    root.left = l
                    root.right = r
                    res.append(root)
        return res

96. 不同的二叉搜索树-Medium

class Solution:
    def numTrees(self, n: int) -> int:
        # numTrees[4] = numTrees[0] * numTrees[3]+
        #               numTrees[3] * numTrees[0]+
        #               numTrees[1] * numTrees[2]+
        #               numTrees[2] * numTrees[1]
        numTree = [1] * (n + 1)
        for nodes in range(2, n + 1):
            total = 0
            for root in range(1, nodes + 1):
                left = root - 1
                right = nodes - root
                total += numTree[left] * numTree[right]
            numTree[nodes] = total
        return numTree[n]

97. 交错字符串-Medium

class Solution:
    def isInterleave(self, s1: str, s2: str, s3: str) -> bool:
        n1 = len(s1)
        n2 = len(s2)
        n = len(s3)
        if n1+n2 != n:
            return False
        # dp(i,j)表示是s1的前i个字符和s2的前j个字符能否交错成s3的前i+j个字符
        # 因此答案为dp(n1,n2)
        dp = [[False for _ in range(n2+1)] for _ in range(n1+1)]
        dp[0][0] = True
        # 初始化dp[0][i]和dp[i][0]
        for i in range(1,n1+1):
            dp[i][0] = dp[i-1][0] and (s1[i-1] == s3[i-1])
        for i in range(1,n2+1):
            dp[0][i] = dp[0][i-1] and (s2[i-1] == s3[i-1])
        # 填写dp
        for i in range(1,n1+1):
            for j in range(1,n2+1):
                dp[i][j] = (dp[i-1][j] and s1[i-1] == s3[i+j-1]) or (dp[i][j-1] and 
                s2[j-1] == s3[i+j-1])
        return dp[n1][n2]  

98. 验证二叉搜索树-Medium

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isValidBST(self, root: TreeNode) -> bool:
        return self.valid(root, float('-inf'), float('inf'))


    def valid(self, root, min, max):
        if not root:
            return True
        if root.val >= max or root.val <= min: return False
        return self.valid(root.left, min, root.val) and self.valid(root.right, root.val, max)

99. 恢复二叉搜索树-Hard

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def recoverTree(self, root: TreeNode) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        self.fnode = None
        self.snode = None
        self.preNode = TreeNode(float("-inf"))

        def order(root):
            if not root:
                return 
            order(root.left)
            if self.snode == None and self.preNode.val >= root.val:
                self.fnode = self.preNode
            if self.fnode and self.preNode.val >= root.val:
                self.snode = root
            self.preNode = root
            order(root.right)

        order(root)
        self.fnode.val , self.snode.val = self.snode.val , self.fnode.val

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def recoverTree(self, root: TreeNode) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        fnode = None
        snode = None
        pre = TreeNode(float("-inf"))

        stack = []
        p = root
        while p or stack:
            while p:
                stack.append(p)
                p = p.left
            p = stack.pop()
            if not fnode and pre.val > p.val: #这是存在异常的情况
                fnode = pre  #找到第一个位置的异常点
            if fnode and pre.val > p.val:
                snode = p  #找到第二个位置的异常点,因为题意说了,只有两个异常,所以无论两者是否挨在一起,只要交换过来值,就一定是对的,此代码不具有泛化性
            
            pre = p
            p = p.right
        fnode.val,snode.val = snode.val,fnode.val

100. 相同的树-Easy

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
        if p is None and q is None:
            return True
        if p is not None and q is not None:
            return p.val == q.val and self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
        return False

你可能感兴趣的:(python,数据结构)