[刷题] Leetcode算法 (2020-3-1)

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

题目:

给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

示例:

输入: 1->1->2->3->3
输出: 1->2->3

代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        # 如果head为空,返回None
        if not head:
            return None
        # temp作为前后比较的指针,初始指向head
        temp = head
        # res作为结果链表的指针,初始指向head
        res = head
        # 如果还有下一个节点,则前后比较val
        while temp.next:
            # 如果前后不相等
            if temp.val != temp.next.val:
                # 让res指向后面那个
                res.next = temp.next
                # res移一个节点
                res = res.next
            temp = temp.next
        # 循环结束的时候可能最后几个是相同的,扔掉最后几个相同的,只取res指向的那个节点
        res.next = None

        return head

2.合并两个有序数组

题目:

给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。

说明:

初始化 nums1 和 nums2 的元素数量分别为 m 和 n。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。

示例:

输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6],       n = 3

输出: [1,2,2,3,5,6]

代码:

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.
        """
        
        p1=m-1  # 获取nums1的最大索引
        p2=n-1  # 获取nums2的最大索引
        p=m+n-1  # 获取合并后nums1的最大索引
        # 两个列表都还有值
        while p1>=0 and p2>=0:
            # 谁大,谁放后面
            if nums1[p1]<nums2[p2]:
                nums1[p]=nums2[p2]
                p2-=1
            else:
                nums1[p]=nums1[p1]
                p1-=1
            # p向前移一格
            p-=1
        # 某个列表没有元素了(假设nums1没有元素了,则剩下的nums2直接拷贝到最前面)(假设nums2没有元素了p2+1=0,所以下面语句不会赋值元素)
        nums1[:p2+1]=nums2[:p2+1]

总结:

# 这种in-place合并问题,我们可以找到一个正确的方向来写入值,在写入的同时不影响本身还未使用的元素
# 这里我们就选择从nums1的最后(合并后总长度)开始向前按顺序存放值,这样在存放的过程中也不会影响nums1和nums2中途未使用的元素

3.相同的树

题目:

给定两个二叉树,编写一个函数来检验它们是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例:

输入:       1         1
          /        / 
         2   3     2   3

        [1,2,3],   [1,2,3]

输出: true

输入:       1         1
          /        / 
         2   1     1   2

        [1,2,1],   [1,1,2]

输出: false

代码1:

class Solution:
    def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
        
        """
        :type p: TreeNode
        :type q: TreeNode
        :rtype: bool
        """    
        # 如果都为None,则相等
        if not p and not q:
            return True
        # 如果其中有一个为None,另一个不是None,则不相等
        if not q or not p:
            return False
        # p和q的val不同,不相等
        if p.val != q.val:
            return False
        # p和q的左右子节点分别相同,才相同
        return self.isSameTree(p.right, q.right) and 
               self.isSameTree(p.left, q.left)

递归解法。

时间复杂度 : O(N),其中 N 是树的结点数,因为每个结点都访问一次。

空间复杂度 : 最优情况(完全平衡二叉树)时为 O(log(N)),最坏情况下(完全不平衡二叉树)时为O(N),用于维护递归栈。

代码2:

from collections import deque
class Solution:
    def isSameTree(self, p, q):
        """
        :type p: TreeNode
        :type q: TreeNode
        :rtype: bool
        """    
        # 定义内部函数,用于判断两个节点是否相同
        def check(p, q):
            # if both are None
            if not p and not q:
                return True
            # one of p and q is None
            if not q or not p:
                return False
            if p.val != q.val:
                return False
            return True
        
        # 使用队列,先将p和q的根节点作为pair元组加入队列(按对加入很重要)
        deq = deque([(p, q),])
        # 当队列中还有pair的时候,就要进行比对,知道队列为空,或者出现不同的对
        while deq:
            # 一对一对拿出来比对
            p, q = deq.popleft()
            # 只要有一对不同,则返回false
            if not check(p, q):
                return False
            # 只要p树还有节点
            if p:
                # 将p的左 q的左做成一对加入队列
                deq.append((p.left, q.left))
                # 将p的右 q的右做成一对加入队列
                deq.append((p.right, q.right))
                    
        return True

迭代解法。

时间复杂度 : O(N),其中 N 是树的结点数,因为每个结点都访问一次。

空间复杂度 : 最优情况(完全平衡二叉树)时为 O(log(N)),最坏情况下(完全不平衡二叉树)时为 O(N)。

总结:

# 递归做法比较简洁,但是每轮递归都要开辟栈空间。
# 迭代做法利用了一个队列,由于比较树形结构,所以将其对应节点做为pair是非常好的思想

4.对称二叉树

题目:

给定一个二叉树,检查它是否是镜像对称的。

说明:

如果你可以运用递归和迭代两种方法解决这个问题,会很加分。

示例:

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

    1
   / 
  2   2
 /  / 
3  4 4  3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:

    1
   / 
  2   2
      
   3    3

代码1:

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        # 递归,传入判断是否对称的两个节点
        def ismirror(left,right):
            # 如果都为空,表示对称
            if not left and not right:
                return True
            # 如果只有一个为空,则不对称
            if not left or not right:
                return False
            # 如果都不为空,但val不同,也不对称
            if left.val != right.val:
                return False
            # 在当前两个节点对称的情况下,分别在求他们的子节点的是否都对称
            return ismirror(left.left, right.right) and ismirror(left.right,right.left)

        return ismirror(root,root)

递归解法。

代码2:

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        from collections import deque
        if not root:
            return True
        deq = deque([(root.left, root.right),])
        # st=[root.left,root.right]
        while deq:
            l,r=deq.popleft()
            if not l and not r:
                continue
            elif not l or not r:
                return False
            elif l.val!=r.val:
                return False
            else:
                deq.append((l.left,r.right))
                deq.append((l.right,r.left))
        return True

迭代做法,和前面的第3题一样,差不多的思路。

总结:

# 二叉树是否对称和前面第3题(两个二叉树是否相等)思路基本一致
# 二叉树是否对称,可以看成 自己和自己的镜像是否完全相等
# 所以两道题的递归做法和迭代做法都是很相似的

###

原文地址:https://www.cnblogs.com/leokale-zz/p/12392387.html