Leetcode题medium73/74/75/78/79/80/81/90/105/106,Python多种解法(五)

前文

  继上一篇Leetcode题medium48/54/55/56/59/62/63/64,Python多种解法(四),我们继续Array medium题目的解法分享。

73. Set Matrix Zeroes

class Solution(object):
    """
    讨论区清晰易懂解法,每步的含义都有英文注释,简单说就是把第一行和第一列作为标记位,如果第一次双重遍历有发现为0,则标记
    第一行和第一列对应的那个数为0,第二次双重遍历把该填的0填上即可。
    要注意的是填充0的话,j是从末尾开始往前填,因为如果从0开始往后填,则如果第一行第一个为0的话会把第一列全填为0,此时每行也
    因为第一行全变为0
    Runtime: 92 ms, faster than 61.68% of Python online submissions for Set Matrix Zeroes.
    Memory Usage: 11.1 MB, less than 44.39% of Python online submissions for Set Matrix Zeroes.
    """
    def setZeroes(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: None Do not return anything, modify matrix in-place instead.
        """
        # First row has zero?
        m, n, firstRowHasZero = len(matrix), len(matrix[0]), not all(matrix[0])
        # Use first row/column as marker, scan the matrix
        for i in range(1, m):
            for j in range(n):
                if matrix[i][j] == 0:
                    matrix[0][j] = matrix[i][0] = 0
        # Set the zeros
        for i in range(1, m):
            for j in range(n - 1, -1, -1):
                if matrix[i][0] == 0 or matrix[0][j] == 0:
                    matrix[i][j] = 0
        # Set the zeros for the first row
        if firstRowHasZero:
            matrix[0] = [0] * n
74. Search a 2D Matrix

class Solution(object):
    """
    原理很简单,普通二分法,关键要知道如何转换列表索引为矩阵索引,即num = matrix[mid/cols][mid%cols]
    Runtime: 20 ms, faster than 100.00% of Python online submissions for Search a 2D Matrix.
    Memory Usage: 11.4 MB, less than 55.04% of Python online submissions for Search a 2D Matrix.
    """
    def searchMatrix(self, matrix, target):
        """
        :type matrix: List[List[int]]
        :type target: int
        :rtype: bool
        """
        if not matrix or target is None:
            return False

        rows, cols = len(matrix), len(matrix[0])
        low, high = 0, rows * cols - 1
        
        while low <= high:
            mid = (low + high) / 2
            num = matrix[mid / cols][mid % cols]

            if num == target:
                return True
            elif num < target:
                low = mid + 1
            else:
                high = mid - 1
        
        return False

class Solution2(object):
    """
    直接用双重遍历的方式来解决,复杂度是O(m*n),但惊讶的是时间与二分法相差不大
    Runtime: 20 ms, faster than 100.00% of Python online submissions for Search a 2D Matrix.
    Memory Usage: 11.7 MB, less than 9.30% of Python online submissions for Search a 2D Matrix.
    """
    def searchMatrix(self, matrix, target):
        """
        :type matrix: List[List[int]]
        :type target: int
        :rtype: bool
        """
        if not matrix or not matrix[0]: return False
        for i in range(len(matrix)):
            if target==matrix[i][-1]: return True
            elif target<matrix[i][-1]:
                for j in range(len(matrix[0])):
                    if matrix[i][j]==target: return True
                return False
        return False
75. Sort Colors

class Solution(object):
    """
    解题的思路就是定义nums[:j]存放的是0,nums[k:]存放的是2,这样剩余中间的即是1
    代码是用快慢两个指针,也就是i,j,当j碰到0就和i调换,即使此时的nums[i]是不是0,调换后i+1,然后j会再做一次判断
    同理的nums[j]==2也是这样处理
    Runtime: 20 ms, faster than 98.75% of Python online submissions for Sort Colors.
    Memory Usage: 10.8 MB, less than 40.74% of Python online submissions for Sort Colors.
    """
    def sortColors(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        i = 0
        k = len(nums)-1
        j = i
        while j <= k:
            if i < j and nums[j] == 0:
                nums[i], nums[j] = nums[j], nums[i]
                i += 1
            elif nums[j] == 2:
                nums[j], nums[k] = nums[k], nums[j]
                k -= 1
            else:
                j += 1


class Solution2(object):
    """
    这个解法太强了,因为题目的限制是原地变动,基本就没想过用额外空间的方法,而下述代码则直接绕过创空间来实现
    Runtime: 20 ms, faster than 98.75% of Python online submissions for Sort Colors.
    Memory Usage: 10.6 MB, less than 90.57% of Python online submissions for Sort Colors.
    """
    def sortColors(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        c0 = c1 = c2 = 0
        for num in nums:
            if num == 0:
                c0 += 1
            elif num == 1:
                c1 += 1
            else:
                c2 += 1
        nums[:c0] = [0] * c0
        nums[c0:c1+c1] = [1] * c1
        nums[c0+c1:] = [2] * c2
78. Subsets


class Solution(object):
    """
    迭代解法:代码的实现真的很巧妙,结合规律,以题目为例:
    [1,2,3]答案里:[]
                  [1],[1,2],[1,3],[1,2,3]
                  [2],[2,3]
                  [3]
    即每遍历一个数,新加入[]+[num];然后再在已拥有的集合里增加新的数,比如3,已有的集合就是:[1],[1,2],[2],
    依次转换为[1,3],[1,2,3],[2,3]
    Runtime: 24 ms, faster than 100.00% of Python online submissions for Subsets.
    Memory Usage: 11 MB, less than 37.77% of Python online submissions for Subsets.
    """
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = [[]]
        for num in nums:
            for i in range(len(res)):
                res.append(res[i]+[num])
        return res

class Solution2(object):
    """
    递归解法:原理和迭代是一致的,但因为是递归,所以理解起来稍微费脑
    该解法从最后一次递归返回结果开始,然后跟迭代一致的想法,在上一个结果的基础上,依次增加当前数;
    以[1,2,3]为例,第一次递归返回:[],[3],此时的head为2,所以for遍历后结果为:[],[3],[2],[3,2]
    接着得到的res再次返回,此时head为1,所以再依次加上得:[1],[3,1],[2,1],[3,2,1]
    Runtime: 24 ms, faster than 100.00% of Python online submissions for Subsets.
    Memory Usage: 11 MB, less than 50.82% of Python online submissions for Subsets.
    """
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """

        def helper(nums, i, j):
            if i > j:
                return [[]]
            if j - i == 1:
                return [[], [nums[i]]]
            head = nums[i]
            res = helper(nums, i + 1, j)
            for i in range(len(res)):
                res.append(res[i] + [head])
            return res

        return helper(nums, 0, len(nums))
79. Word Search


class Solution(object):
    """
    循环查找的还是递归最实用,讨论区的大神答案,英文注释就已经写得非常清楚!
    Runtime: 300 ms, faster than 32.05% of Python online submissions for Word Search.
    Memory Usage: 14.1 MB, less than 39.51% of Python online submissions for Word Search.
    """
    def exist(self, board, word):
        """
        :type board: List[List[str]]
        :type word: str
        :rtype: bool
        """
        if not board:
            return False
        for i in range(len(board)):
            for j in range(len(board[0])):
                if self.dfs(board,i,j,word):
                    return True
        return False
    
    # check whether can find word, start at (i,j) position    
    def dfs(self, board, i, j, word):
        if len(word) == 0: # all the characters are checked
            return True
        if i<0 or i>=len(board) or j<0 or j>=len(board[0]) or word[0]!=board[i][j]:
            return False
        tmp = board[i][j]  # first character is found, check the remaining part
        board[i][j] = "#"  # avoid visit agian 
        # check whether can find "word" along one direction
        res = self.dfs(board, i+1, j, word[1:]) or self.dfs(board, i-1, j, word[1:]) \
        or self.dfs(board, i, j+1, word[1:]) or self.dfs(board, i, j-1, word[1:])
        board[i][j] = tmp
        return res
80. Remove Duplicates from Sorted Array II

class MySolution(object):
    """
    思路简单,从第2个开始比,如果和前两个来的一致,则删除该数,否则继续
    Runtime: 36 ms, faster than 86.94% of Python online submissions for Remove Duplicates from Sorted Array II.
    Memory Usage: 10.5 MB, less than 99.09% of Python online submissions for Remove Duplicates from Sorted Array II.
    """
    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) <= 2:
            return
        index = 2
        while index and index <= len(nums)-1:
            if nums[index] == nums[index-1] and nums[index] == nums[index-2]:
                nums.pop(index)
            else:
                index += 1
        return index
        

class Solution(object):
    """
    讨论区答案,一次遍历,当i>2的时候,如果遍历到的数增大则交换i的位置,否则继续遍历
    Runtime: 32 ms, faster than 100.00% of Python online submissions for Remove Duplicates from Sorted Array II.
    Memory Usage: 10.9 MB, less than 5.45% of Python online submissions for Remove Duplicates from Sorted Array II.
    [1,1,1,2,2,3]
    """
    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        i = 0
        for n in nums:
            if i < 2 or n > nums[i-2]:
                nums[i] = n
                i += 1
        return i
        
81. Search in Rotated Sorted Array II

class Solution(object):
    """
    英文注释写的比较清楚了,要注意的是代码核心是围绕分割成左边为有序序列或者右边为有序序列这条来实现的,那要达到左边是有序
    序列的前提则左边一开始不能有等于nums[mid]的数,所以嵌套了while来解决,而右边是不需要的,因为右边即使等同于nums[mid],
    则也一直都是有序序列,如果套上while,反而使原本是O(logN)变成了O(N)
    Runtime: 20 ms, faster than 99.76% of Python online submissions for Search in Rotated Sorted Array II.
    Memory Usage: 11 MB, less than 5.66% of Python online submissions for Search in Rotated Sorted Array II.
    """
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: bool
        """
        l, r = 0, len(nums)-1
        while l <= r:
            mid = l + (r-l)//2
            if nums[mid] == target:
                return True
            while l < mid and nums[l] == nums[mid]: # tricky part
                l += 1
            # the first half is ordered
            if nums[l] <= nums[mid]:
                # target is in the first half
                if nums[l] <= target < nums[mid]:
                    r = mid - 1
                else:
                    l = mid + 1
            # the second half is ordered
            else:
                # target is in the second half
                if nums[mid] < target <= nums[r]:
                    l = mid + 1
                else:
                    r = mid - 1
        return False
90. Subsets II
class Solution(object):
    """
    利用for+递归来实现,针对序列里的每个数,递归找到所有组合;而针对序列的每个数再做判断,如果相似就跳过
    Runtime: 28 ms, faster than 100.00% of Python online submissions for Subsets II.
    Memory Usage: 10.9 MB, less than 65.26% of Python online submissions for Subsets II.
    """
    def subsetsWithDup(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = []
        nums.sort()
        self.dfs(nums, 0, [], res)
        return res
    
    def dfs(self, nums, index, path, res):
        res.append(path)
        for i in range(index, len(nums)):
            if i > index and nums[i] == nums[i-1]:
                continue
            self.dfs(nums, i+1, path+[nums[i]], res)




class Solution2(object):
    """
    Use a dictionary to keep track of the number of appearances of each number. One can then easily construct the power set of nums based on this dictionary.

    E.g., nums = [1,1,2,2,2,4,4,5]. In this case dic = {1:2, 2:3, 4:2, 5:1}. We intialize res = [[]], and build the solution iteratively as we loop over the dictionary. We first reach key, val = 1, 2. The power set of [1,1] is res = [[], [1], [1,1]]. Then we reach key, val = 2, 3. The power set of [1,1,2,2,2] is obtained by appending either 0, 1, 2, or 3 2's to all elements in res. After which we get res = [[], [1], [1,1], [2], [1,2], [1,1,2],[2,2], [1,2,2], [1,1,2,2],[2,2,2], [1,2,2,2], [1,1,2,2,2]]. After we loop over dic, res will be the power set of nums.

    Time complexity: O(2^n), space complexity: O(2^n).
    Runtime: 32 ms, faster than 91.48% of Python online submissions for Subsets II.
    Memory Usage: 10.7 MB, less than 100.00% of Python online submissions for Subsets II.
    """
    def subsetsWithDup(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        if not nums:
            return [[]]
        res = [[]]
        dic = collections.Counter(nums)
        for key, val in dic.items():
            tmp = []
            for lst in res:
                for i in range(1, val+1):
                    tmp.append(lst+[key]*i)
            res += tmp
        return res
105. Construct Binary Tree from Preorder and Inorder Traversal

# 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):
    """
    给出树的前序遍历和中序遍历推导树原来的样子,先定位到root的index,然后递归查找左子树和右子树即可
    Runtime: 188 ms, faster than 36.05% of Python online submissions for Construct Binary Tree from Preorder and Inorder Traversal.
    Memory Usage: 85.4 MB, less than 15.96% of Python online submissions for Construct Binary Tree from Preorder and Inorder Traversal.
    """
    def buildTree(self, preorder, inorder):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode
        """
        if len(preorder) == 0:
            return None
        if len(preorder) == 1:
            return TreeNode(preorder[0])
        root = TreeNode(preorder[0])
        index = inorder.index(root.val)
        root.left = self.buildTree(preorder[1 : index + 1], inorder[0 : index])
        root.right = self.buildTree(preorder[index + 1 : len(preorder)], inorder[index + 1 : len(inorder)])
        return root


class Solution2(object):
    """
    简化了上面的解法,因为前序遍历的第一个数一定就是递归的下一个根节点,利用这一点即可写出更简洁的代码
    Runtime: 116 ms, faster than 65.52% of Python online submissions for Construct Binary Tree from Preorder and Inorder Traversal.
    Memory Usage: 50 MB, less than 53.78% of Python online submissions for Construct Binary Tree from Preorder and Inorder Traversal.
    """
    def buildTree(self, preorder, inorder):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode
        """
        if inorder:
            ind = inorder.index(preorder.pop(0))
            root = TreeNode(inorder[ind])
            root.left = self.buildTree(preorder, inorder[0:ind])
            root.right = self.buildTree(preorder, inorder[ind+1:])
            return root
106. Construct Binary Tree from Inorder and Postorder Traversal

# 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):
    """
    跟105同样的解法
    Runtime: 216 ms, faster than 18.43% of Python online submissions for Construct Binary Tree from Inorder and Postorder Traversal.
    Memory Usage: 85.5 MB, less than 11.47% of Python online submissions for Construct Binary Tree from Inorder and Postorder Traversal.
    """
    def buildTree(self, inorder, postorder):
        """
        :type inorder: List[int]
        :type postorder: List[int]
        :rtype: TreeNode
        """
        if len(inorder) == 0:
            return None 
        if len(inorder) == 1:
            return TreeNode(inorder[0])
        root = TreeNode(postorder[len(postorder) - 1])
        index = inorder.index(postorder[len(postorder) - 1])
        root.left = self.buildTree(inorder[ 0 : index ], postorder[ 0 : index ])
        root.right = self.buildTree(inorder[ index + 1 : len(inorder) ], postorder[ index : len(postorder) - 1 ])
        return root

class Solution2(object):
    """
    跟105同样的解法
    Runtime: 116 ms, faster than 61.08% of Python online submissions for Construct Binary Tree from Inorder and Postorder Traversal.
    Memory Usage: 50 MB, less than 49.18% of Python online submissions for Construct Binary Tree from Inorder and Postorder Traversal.
    """
    def buildTree(self, inorder, postorder):
        """
        :type inorder: List[int]
        :type postorder: List[int]
        :rtype: TreeNode
        """
        if not inorder or not postorder:
            return None
        
        root = TreeNode(postorder.pop())
        inorderIndex = inorder.index(root.val)

        root.right = self.buildTree(inorder[inorderIndex+1:], postorder)
        root.left = self.buildTree(inorder[:inorderIndex], postorder)

        return root

总结

  本次分享到此结束,谢谢~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值