LeetCode-算法:81-100(Python)


81. 搜索旋转排序数组 II

在这里插入图片描述
思路
是33. 搜索旋转排序数组的进阶

  1. 顺序查找最小的数为数组nums有序的分界点
  2. target小于最小的数返回false
  3. target大于等于数组第一个数,则target可能存在数组左边有序序列中,否则target可能存在数组右边有序序列中
  4. 在有序序列中使用二分查找target
class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: bool
        """
        # 顺序查找最小的数为数组nums有序的分界点
        def findMin(nums):
            i, n = 0, len(nums)
            for j in range(1, n):
                if nums[j] >= nums[i]:
                    i += 1
                else:
                    return j    # 如果nums[j]小于nums[i],返回j。当最小的数有数个,返回最左边的那个
            return 0    # 列表有序,最小的数在第0位
        # 二分查找
        def binary(nums, target):
            l, r = 0, len(nums) - 1
            while l <= r:
                mid = (l + r)//2
                if nums[mid] == target:
                    return True
                elif nums[mid] > target:
                    r = mid - 1
                else:
                    l = mid + 1
            return False
            
        l, r = 0, len(nums)-1
        mini = findMin(nums)
        if not nums or target < nums[mini]:
            return False
        if mini == l:    # # mini在第一位,直接使用二分查找
            return binary(nums, target)
        if target >= nums[l]:
            return binary(nums[0:mini], target)
        else:
            return binary(nums[mini:], target)

思路
O(∩_∩)O哈哈~

class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: bool
        """
        return True if target in nums else False



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

在这里插入图片描述
思路
是83. 搜索旋转排序数组的进阶

  1. 当head为空或只有一个结点时,直接返回
  2. 创建左指针l指向第一个结点和右指针指r向第二个结点,r往右遍历
    • 当l.val不等于r.val时:
      • 如果r是否在l右边一个位置,证明l.val只有一个,则保存l.val至返回的链表中,且cur往右移动一位
      • 如果r不在l右边一个位置,证明l.val有重复结点,则更新l=r
    • 当l.val等于r.val时:r = r.next,r指向下一位进入下个循环
    • 最后,如果l.val是最后一个结点,证明l.val只有一个数没有重复(如果l不在最后一个位置,证明最后结点的数有重复)
  3. 返回没有重复数字结点的链表rehead.next
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head or head.next == None:
            return head
        l, r = head, head.next
        rehead = ListNode(None)
        cur = rehead
        while r != None:
            if l.val != r.val:
                if l.next == r:
                    cur.next = ListNode(l.val)
                    cur = cur.next
                l = r
            r = r.next
        if l.next == None:
            cur.next = ListNode(l.val)
            
        return rehead.next



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

在这里插入图片描述
思路
是26. 删除排序数组中的重复项的链表形式,双指针

  1. 当head为空或只有一个结点时,直接返回
  2. 创建左指针l指向第一个结点和右指针指r向第二个结点,r往右遍历
    • 当l.val不等于r.val时:l指向下一个位置,并令l.val = r.val
    • 当l.val等于r.val时:r = r.next,r指向下一位进入下个循环
    • 最后,l.next = None删除后面多余的结点
  3. 返回head
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head or head.next == None:
            return head

        l, r = head, head.next
        while r != None:
            if l.val != r.val:
                l = l.next
                l.val = r.val
            r = r.next
        l.next = None
        return head



84. 柱状图中最大的矩形

在这里插入图片描述
思路

  1. 当柱子heights[i]的高度大于前方的柱子时,将柱子下标i存在列表stack(栈)中。
  2. 当柱子heights[i]的高度小于等于前方柱子时,在stack栈顶的下标为i-1比i高的柱子,此时,计算i前方的柱子面积。如栈顶stack.pop()是i-1,则高度为heights[i-1],宽度为i减pop掉heights[i-1]后的栈顶再减1。(heights[stack[-1]] >= heights[i],柱子i-1比柱子i高,从i-1柱子往左直到柱子j(j<i-1)比i矮,高度为i-1到j+1递减,宽度1到i-j-1递增。为计算面积)。计算后更新max_area。当柱子heights[i]的高度小于前方柱子heights[i-1]时,添加i至stack中。
  3. 最后,剩下升序排列的柱子,i到了n的位置,与2同理计算面积与max_area比较后更新max_area
class Solution(object):
    def largestRectangleArea(self, heights):
        """
        :type heights: List[int]
        :rtype: int
        """
        n = len(heights)
        if not n:
            return 0
        stack, max_area = list(), 0
        stack.append(-1)
        for i in range(n):
            while stack[-1] != -1 and heights[stack[-1]] >= heights[i]:
                max_area = max(max_area, heights[stack.pop()]*(i-stack[-1]-1))
            stack.append(i)
        while stack[-1] != -1:
            max_area = max(max_area, heights[stack.pop()]*(n-stack[-1]-1))
        return max_area



85. 最大矩形

在这里插入图片描述
思路
遍历每一行求84. 柱状图中最大的矩形
栗子:
matrix = [
[“1”,“0”,“1”,“0”,“0”],
[“1”,“0”,“1”,“1”,“1”],
[“1”,“1”,“1”,“1”,“1”],
[“1”,“0”,“0”,“1”,“0”]
]
第一行的柱状图heights: [1, 0, 1, 0, 0]
第二行的柱状图heights: [2, 0, 2, 1, 1]
第三行的柱状图heights: [3, 1, 3, 2, 2]
第四行的柱状图heights: [4, 0, 0, 3, 0]

class Solution(object):
    def maximalRectangle(self, matrix):
        """
        :type matrix: List[List[str]]
        :rtype: int
        """
        if not matrix:
            return 0
   
        def largestRectangleArea(heights):
            stack, max_area = list(), 0
            stack.append(-1)
            for i in range(n):
                while stack[-1] != -1 and heights[stack[-1]] >= heights[i]:
                    max_area = max(max_area, heights[stack.pop()]*(i-stack[-1]-1))
                stack.append(i)
            while stack[-1] != -1:
                max_area = max(max_area, heights[stack.pop()]*(n-stack[-1]-1))
            return max_area

        m, n, max_area = len(matrix), len(matrix[0]), 0
        heights = [0]*n
        for i in range(m):
            for j in range(n):
                heights[j] =heights[j] + 1 if matrix[i][j]=='1' else 0
        #     print(heights)
            max_area = max(max_area, largestRectangleArea(heights))
        return max_area



86. 分隔链表

在这里插入图片描述
思路
栗子:

head -> 1 -> 4 -> 3 -> 2 -> 5 -> 2
x = 3
##############################
r,rehead
0 -> 1 -> 4 -> 3 -> 2 -> 5 -> 2

    r,l
0 -> 1 -> 4 -> 3 -> 2 -> 5 -> 2
  
     l         r    t       
0 -> 1 -> 4 -> 3 -> 2 -> 5 -> 2

     l    t         r      
0 -> 1 -> 2 -> 4 -> 3 -> 5 -> 2

          l         r     
0 -> 1 -> 2 -> 4 -> 3 -> 5 -> 2
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def partition(self, head, x):
        """
        :type head: ListNode
        :type x: int
        :rtype: ListNode
        """
        if not head or head.next == None:
            return head
        r = ListNode(0)
        r.next = head
        rehead = r
        while r.next != None and r.next.val < x:    # 当结点小于x时,r往右走直到r.next.val大于x,作为第一个可插入的位置
            r = r.next
        l = r    # l 指向 r,记录插入位置的前置结点

        while r.next != None:
            while r.next != None and r.next.val >= x:    # 当r.next.val大于等于x时,往右走寻找小于x的结点
                r = r.next
            if r.next !=None:
                t = r.next    # t保存小于x的结点
                r.next = r.next.next    # r指向t后面的结点,将t结点提取出来
                t.next = l.next    # t结点指向l的下一个结点
                l.next = t    # l结点连接t结点
                l = l.next    # 更新l

        return rehead.next



87. 扰乱字符串

在这里插入图片描述
在这里插入图片描述
思路
递归:

  1. 当字符串长度不相等及字符串排序后不相等返回False
  2. 当字符串相等时返回True
  3. 递归条件:1.s1的前i个字符与s2的前i个字符相等及s1的后n-i个字符与s2的后n-i个字符相等;2.s1的前i个字符与s2的后i个字符相等及s1的后n-i个字符与s2的前n-i个字符相等
class Solution(object):
    def isScramble(self, s1, s2):
        """
        :type s1: str
        :type s2: str
        :rtype: bool
        """
        n1, n2 = len(s1), len(s2)
        if n1 != n2:    # 字符串长度不相等
            return False
        if sorted(s1) != sorted(s2):    # 字符串的字符不相等
            return False
        if s1 == s2:    # 字符串相等
            return True
        for i in range(1, n1):
            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



88. 合并两个有序数组

在这里插入图片描述
思路
sort(): 对list排序会修改list本身,不会返回新list
sorted(): 返回的排序后的 list

class Solution(object):
    def merge(self, nums1, m, nums2, n):
        """
        :type nums1: List[int]
        :type m: int
        :type nums2: List[int]
        :type n: int
        :rtype: None Do not return anything, modify nums1 in-place instead.
        """
        nums1[:] = sorted(nums1[:m] + nums2[:n])
        return nums1



89. 格雷编码

在这里插入图片描述
思路

格雷码-百度百科
递归生成码表
这种方法基于格雷码是反射码的事实,利用递归的如下规则来构造:

  1. 1位格雷码有两个码字
  2. (n+1)位格雷码中的前2n个码字等于n位格雷码的码字,按顺序书写,加前缀0
  3. (n+1)位格雷码中的后2n个码字等于n位格雷码的码字,按逆序书写,加前缀1
  4. n+1位格雷码的集合 = n位格雷码集合(顺序)加前缀0 + n位格雷码集合(逆序)加前缀1
1位格雷码2位格雷码3位格雷码
000000
101001
-11011
-10010
--110
--111
--101
--100
class Solution(object):
    def grayCode(self, n):
        """
        :type n: int
        :rtype: List[int]
        """
        def gray(n):
            if n == 0:
                return ["0"]
            if n == 1:
                return ["0", "1"]
            ans = list()
            for num in gray(n-1):
                ans.append("0"+num)
            for num in reversed(gray(n-1)):
                ans.append("1"+num)
            return ans 
            
        return list(map(lambda num:int(num, 2), gray(n)))



90. 子集 II

在这里插入图片描述
思路
是78. 子集的进阶

  1. 对nums进行排序
  2. 去除重复元素
class Solution(object):
    def subsetsWithDup(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        nums.sort()
        ans = [[]]
        for num in nums:
            ans += [pre+[num] for pre in ans if pre+[num] not in ans]
        return ans



91. 解码方法

在这里插入图片描述
思路

  1. s为空或第一个字符为0,返回0
  2. 创建dp数组,初始化dp数组第一个数为1
  3. 遍历s字符串:
    • 当s[i]等于0时,如果前一个字符是1或2,说明s[i-1:i+1]只有一种编码,因此dp[i]=dp[i-2]。如果前一个字符不为0或1(如00,30,40…),说明字符串没有合法编码,故返回0
    • 当s[i]等于1或2时,与前一个字符在11~26范围内,说明s[i-1:i+1]有两种编码,因此dp[i]=dp[i-1]+dp[i-2]
    • 当s[i]在3~9范围内,说明s[i]只有一种编码,因此dp[i] = dp[i-1]
  4. 返回dp[-1]
class Solution(object):
    def numDecodings(self, s):
        """
        :type s: str
        :rtype: int
        """
        if not s or s[0]=="0":    # s为空或第一个字符为0,返回0
            return 0
        n = len(s)
        dp = [None]*n    # 创建dp数组
        dp[0] = 1    # 初始化dp数组第一个数为1
        for i in range(1, n):
            if s[i] == "0":    
                if s[i-1] == "1" or s[i-1] == "2":
                    dp[i] = dp[i-2] if i > 1 else dp[i-1]
                else:
                    return 0
            elif (s[i-1] == "1" and int(s[i])<=9) or (s[i-1] == "2" and int(s[i]) <= 6): 
                dp[i] = dp[i-1] + dp[i-2] if i > 1 else dp[i-1]+1
            else:
                dp[i] = dp[i-1]
        return dp[-1]



92. 反转链表 II

在这里插入图片描述
思路
参考25. K 个一组翻转链表
栗子:

head -> 1 -> 2 -> 3 -> 4 -> 5
m, n = 2, 4
##############################
p,pre,tail
-1 -> 1 -> 2 -> 3 -> 4 -> 5

p    pre           tail
-1 -> 1 -> 2 -> 3 -> 4 -> 5
  
p    pre      tail  cur     
-1 -> 1 -> 3 -> 4 -> 2 -> 5

p    pre  tail cur
-1 -> 1 -> 4 -> 3 -> 2 -> 5
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def reverseBetween(self, head, m, n):
        """
        :type head: ListNode
        :type m: int
        :type n: int
        :rtype: ListNode
        """
        p = ListNode(-1)
        p.next = head
        pre, tail = p, p
        tmp = list
        while m-1 > 0:    # 寻找第m-1结点作为前置结点pre
            pre = pre.next
            m -= 1
        while n > 0:    # 寻找第n个结点作为tail
            tail = tail.next
            n -= 1
        while pre.next != tail:    # 寻找第n个结点作为tail
            cur = pre.next
            pre.next = cur.next
            cur.next = tail.next
            tail.next = cur
        return p.next



93. 复原IP地址

在这里插入图片描述
思路
回溯:

  1. 结束条件:创建tmp保持临时结果,当tmp长度为4,s字符串为空时,添加tmp至ans
  2. 添加有效字符串至ans,有效范围在0-255之间,长度在1到3为之间
class Solution(object):
    def restoreIpAddresses(self, s):
        """
        :type s: str
        :rtype: List[str]
        """
        def backtrack(s, tmp=list()):
            if len(tmp) == 4:    # 当tmp长度等于4,s字符串没有字符时,添加tmp至ans
                if not s:
                    ans.append(".".join(tmp))
                return
            for cur in range(1, min(4, len(s)+1)): # 因为列表s[:cur]的区间是[),所以cur取值最大为len(s)
                if int(s[:cur])<0 or int(s[:cur]) > 255 or (cur > 1 and s[0]=="0"):
                    break
                backtrack(s[cur:],tmp+[s[:cur]])
        
        ans = list()
        backtrack(s)
        return ans



94. 二叉树的中序遍历

在这里插入图片描述
思路
树的遍历顺序根据遍历的顺序分为先序、中序、后序:

  • 先序:根左右
  • 中序:左根右
  • 后序:左右根

递归

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def inorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        def helper(root, ans=list()):
            if root == None:
                return []
            helper(root.left)
            ans.append(root.val)
            helper(root.right)
            return ans
        return helper(root)
def inorder(root):
    return [] if root == None else inorder(root.left) + [root.val] + inorder(root.right)

思路
栈实现

class Solution(object):
    def inorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        stack, ans = list(), list()
        while root or stack:
            while root != None:
                stack.append(root)
                root = root.left
            root = stack.pop()
            ans.append(root.val)
            root = root.right
        return ans



95. 不同的二叉搜索树 II

在这里插入图片描述
思路
递归:
从1到n的数作为根结点,left(start, i-1)递归构建左子树,(i+1, end)递归构建右子树

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def generateTrees(self, n):
        """
        :type n: int
        :rtype: List[TreeNode]
        """
        def __generateTrees(start, end):
            if start > end:
                return [None]
            ans = list()
            for i in range(start, end+1):
                left = __generateTrees(start, i-1)
                right = __generateTrees(i+1, end)
                for l in left:
                    for r in right:
                        root = TreeNode(i)
                        root.left = l
                        root.right = r
                        ans.append(root)
            return ans
        return __generateTrees(1, n) if n else []



96. 不同的二叉搜索树

在这里插入图片描述
思路

卡特兰数_百度百科
卡特兰数 C n C_n Cn满足以下递推关系:

  1. C n + 1 = C 0 C n + C 1 C n − 1 + ⋯ + C n C 0 C_n+1 = C_0C_n + C_1C_{n-1} + \cdots + C_nC0 Cn+1=C0Cn+C1Cn1++CnC0
  2. ( n − 3 ) C n = n 2 ( C 3 C n − 1 + C 4 C n − 2 + C 5 C n − 3 + C n − 2 C 4 + C n − 1 C 4 ) (n - 3)C_n = \frac{n}{2}(C_3C_{n-1} + C_4C_{n-2} + C_5C_{n-3} + C_{n-2}C_4 + C_{n-1}C_4) (n3)Cn=2n(C3Cn1+C4Cn2+C5Cn3+Cn2C4+Cn1C4)

h ( n ) h(n) h(n)为catalan数的第 n + 1 n+1 n+1项,令 h ( 0 ) = 1 , h ( 1 ) = 1 h(0)=1,h(1)=1 h(0)=1,h(1)=1,catalan数满足递推式:
h ( n ) = h ( 0 ) × h ( n − 1 ) + h ( 1 ) × h ( n − 2 ) + . . . + h ( n − 1 ) × h ( 0 ) ( n > = 2 ) h(n)= h(0)\times h(n-1)+h(1)\times h(n-2) + ... + h(n-1)\times h(0) (n>=2) h(n)=h(0)×h(n1)+h(1)×h(n2)+...+h(n1)×h(0)(n>=2)
另类递推式:
h ( n ) = h ( n − 1 ) × ( 4 × n − 2 ) / ( n + 1 ) h(n)=h(n-1)\times(4\times n-2)/(n+1) h(n)=h(n1)×(4×n2)/(n+1)

给定节点组成二叉搜索树
给定 n n n个节点,能构成多少种不同的二叉搜索树?
能构成 h ( n ) h(n) h(n)个,这个公式的下标是从 h ( 0 ) h(0) h(0)=1开始

class Solution(object):
    def numTrees(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n == 0:
            return 1
        if n == 1:
            return 1
        return self.numTrees(n-1)*(4*n-2)//(n+1)



97. 交错字符串

在这里插入图片描述
思路

  1. 创建dp
  2. 当s1加s2长度不等于s3长度时,返回False
  3. 当s1,s2为空,s3为空时,dp[0][0]=True;当s1/s2为空时,s2/s1应与s3完全相等;当s1、s2、s3非空时,求递推公式。s1或s2的交错组成s3的前缀,此时dp[i][j]的上面dp[i-1][j]=True且s1[i-1]=s3[i-1+j](s1第i个字符下标为i-1)或 左边dp[i][j-1]=True且s2[j-1]==s3[j-1+i]
class Solution(object):
    def isInterleave(self, s1, s2, s3):
        """
        :type s1: str
        :type s2: str
        :type s3: str
        :rtype: bool
        """
        n1, n2, n3 = len(s1), len(s2), len(s3)
        if n1 + n2 != n3:
            return False 

        dp = [[None]*(n2+1) for _ in range(n1+1)]
        dp[0][0] = True
        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]
        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-1+j]) or (dp[i][j-1] and s2[j-1] == s3[j-1+i])

        return dp[-1][-1]



98. 验证二叉搜索树

在这里插入图片描述
思路
递归(先序):

  1. 当左结点大于根结点或右结点小于根结点时返回False
  2. 递归左子树,原结点在右边,左子树不是二叉搜索树时返回False
  3. 递归右子树,原结点在左边,右子树不是二叉搜索树时返回False
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def isValidBST(self, root):
        """  
        :type root: TreeNode
        :rtype: bool
        """
        def helper(root, left, right):
            if root == None:
                return True
            val = root.val 
            if val <= left or val >= right: 
                return False
            if not helper(root.left, left, val): 
                return False
            if not helper(root.right, val, right): 
                return False
            return True
        return helper(root, float("-inf"), float("inf"))



99. 恢复二叉搜索树

在这里插入图片描述
思路

一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数
节点的右子树只包含大于当前节点的数
所有左子树和右子树自身必须也是二叉搜索树

中序遍历:左根右
先遍历到的结点pre比后遍历到的结点root大,找到错误交换的结点x,y

class Solution(object):
    def recoverTree(self, root):
        """
        :type root: TreeNode
        :rtype: None Do not return anything, modify root in-place instead.
        """
        x, y, pre = None, None, None
        stack = list()
        while root or stack:
            while root != None:
                stack.append(root)
                root = root.left
            root = stack.pop()
            if pre and pre.val > root.val:    # 先遍历到的结点比后遍历到的结点大,找到错误交换的结点
                y = root
                if x == None:
                    x = pre
                else: 
                    break
            pre = root
            root = root.right
            
        x.val, y.val = y.val, x.val



100. 相同的树

在这里插入图片描述
思路

  1. 遍历结束后都为空结点返回True
  2. 其中一个结点为空返回False
  3. 结构相同值不相等返回False
  4. 左子树与右子树均相等
class Solution(object):
    def isSameTree(self, p, q):
        """
        :type p: TreeNode
        :type q: TreeNode
        :rtype: bool
        """
        if p == None and q == None:
            return True
        if p == None or q == None:
            return False
        if p.val != q.val:
            return False
        return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)

小milkmilk同小kk~~O(∩_∩)O哈哈~
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值