LeeCode刷题-II DataWhale &天池

@创建于:20220215

1、Task01 数组

15. 三数之和

排序 + 双指针

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        size = len(nums)
        result = []
        if size < 3:
            return []
        nums = sorted(nums)

        for i in range(size-2):
            if nums[i] > 0:
                return result
            if i>0 and (nums[i] == nums[i-1]):
                continue

            left = i + 1
            right = size - 1
            while left < right:
                three_sum = nums[i] + nums[left] + nums[right]
                if three_sum == 0:
                    result.append([nums[i], nums[left], nums[right]])
                    while (left < right) and (nums[left]==nums[left+1]):
                        left += 1
                    while (left < right) and (nums[right]==nums[right-1]):
                        right -= 1
                    left += 1
                    right -= 1
                elif three_sum < 0:
                    left += 1
                else:
                    right -= 1
        
        return result

26. 删除有序数组中的重复项

双指针
定义两个指针 fast和 slow 分别为快指针和慢指针,快指针表示遍历数组到达的下标位置,慢指针表示下一个不同元素要填入的下标位置,初始时两个指针都指向下标 1。

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        size = len(nums)
        if size<1:
            return 0
        
        slow = 1
        fast = 1
        while fast < size:
            if nums[fast] != nums[fast-1]:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1
        
        return slow

27. 移除元素

使用双指针:右指针 right指向当前将要处理的元素,左指针 left 指向下一个将要赋值的位置。

如果右指针指向的元素不等于 vall,它一定是输出数组的一个元素,我们就将右指针指向的元素复制到左指针位置,然后将左右指针同时右移;

如果右指针指向的元素等于 val,它不能在输出数组里,此时左指针不动,右指针右移一位。

整个过程保持不变的性质是:区间 [0,left 中的元素都不等于 val。当左右指针遍历完输入数组以后,leftt 的值就是输出数组的长度。

这样的算法在最坏情况下(输入数组中没有元素等于 val),左右指针各遍历了数组一次。

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        size = len(nums)
        if size < 1:
            return size
        
        slow = 0
        fast = 0
        while fast < size:
            if nums[fast] == val:
                fast += 1
            else:
                nums[slow] = nums[fast]
                slow += 1
                fast += 1
        
        return slow

2、Task02 链表

21. 合并两个有序链表

官方题解

当 list1 和 list2 都不是空链表时,判断 l1 和 l2 哪一个链表的头节点的值更小,将较小值的节点添加到结果里,当一个节点被添加到结果里之后,将对应链表中的节点向后移一位。

class Solution:
    def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
        prehead = ListNode(-1)

        pre = prehead
        while list1 and list2:
            if list1.val < list2.val:
                pre.next = list1
                list1 = list1.next
            else:
                pre.next = list2
                list2 = list2.next
            pre = pre.next
        
        if list1:
            pre.next = list1
        else:
            pre.next = list2

        return prehead.next

在这里插入图片描述

class Solution:
    def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
        if list1 is None:
            return list2
        elif list2 is None:
            return list1
        elif list1.val <= list2.val:
            list1.next = self.mergeTwoLists(list1.next, list2)
            return list1
        else:
            list2.next = self.mergeTwoLists(list1, list2.next)
            return list2

160. 相交链表

题解1

在这里插入图片描述

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        dictA = dict()

        while headA:
            dictA[headA] = 1
            headA = headA.next
        
        while headB:
            if dictA.get(headB):
                return headB
            headB = headB.next
        return None

题解2,双指针

在这里插入图片描述

# 双指针
class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        A = headA
        B = headB
        while A!=B:
            if A:
                A = A.next
            else:
                A = headB
            if B:
                B = B.next
            else:
                B = headA
        return A

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

https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/

在这里插入图片描述

class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        if not head:
            return head
        
        dummy = ListNode(val=0, next=head)
        cur = dummy

        while cur.next and cur.next.next:
            if cur.next.val == cur.next.next.val:
                x = cur.next.val
                while cur.next and cur.next.val == x:
                    cur.next = cur.next.next
            else:
                cur = cur.next
        
        return dummy.next

3、Task03 栈

155. 最小栈

采用辅助站选择栈内最小值

class MinStack:

    def __init__(self):
        self.stack = []
        self.stack_min = [math.inf]

    def push(self, val: int) -> None:
        self.stack.append(val)
        self.stack_min.append(min(val, self.stack_min[-1]))

    def pop(self) -> None:
        self.stack.pop()
        self.stack_min.pop()

    def top(self) -> int:
        return self.stack[-1]

    def getMin(self) -> int:
        return self.stack_min[-1]

844. 比较含退格的字符串

在这里插入图片描述

class Solution:
    def backspaceCompare(self, s: str, t: str) -> bool:
        def build(ss: str) -> str:
            ret = list()
            for ch in ss:
                if ch != "#":
                    ret.append(ch)
                elif ret:
                    ret.pop()
            return "".join(ret)
        
        return build(s) == build(t)

227. 基本计算器 II

思路

在这里插入图片描述

class Solution:
    def calculate(self, s: str) -> int:
        n = len(s)
        stack = []
        sign = '+'
        num = 0

        for i in range(n):
            if s[i]!=' ' and s[i].isdigit():
                num = num*10 + ord(s[i]) - ord('0')
            if i == (n-1) or s[i] in '+-*/':
                if sign == '+':
                    stack.append(num)
                elif sign =='-':
                    stack.append(-num)
                elif sign =='*':
                    stack.append(stack.pop()*num)
                else:
                    stack.append(int(stack.pop()/num))
                sign = s[i]
                num = 0
        return sum(stack)

4、字符串

680. 验证回文字符串 Ⅱ

贪心算法
在这里插入图片描述在这里插入图片描述

class Solution:
    def validPalindrome(self, s: str) -> bool:

        def check_palindrome(low, high):
            i, j = low, high
            while i < j:
                if s[i] == s[j]:
                    i += 1
                    j -= 1
                else:
                    return False
            return True

        left, right = 0, len(s)-1
        while left < right:
            if s[left] == s[right]:
                left += 1
                right -= 1
            else:
                st1 = check_palindrome(left+1, right)
                st2 = check_palindrome(left, right-1)
                return st1 or st2
        return True

168. Excel表列名称

官方题解
在这里插入图片描述

class Solution:
    def convertToTitle(self, columnNumber: int) -> str:
        res = list()

        while columnNumber > 0:
            ch = (columnNumber-1) % 26 + 1
            res.append(chr(ch-1+ord('A')))
            columnNumber = (columnNumber - ch) // 26
        return ''.join(res[::-1])

394. 字符串解码

官方题解
在这里插入图片描述

class Solution:
    def decodeString(self, s: str) -> str:
        stack = list()

        for c in s:
            if c !=']':
                stack.append(c)
            else:
                # 弹出需要重复的字符
                temp = ''
                while stack[-1] != '[':
                    temp = stack.pop() + temp
                
                # 弹出[
                stack.pop()

                # 弹出倍数数值
                num = ''
                while stack and stack[-1].isdigit():
                    num = stack.pop() + num
                num = int(num)

                # 获得按倍数重复的字符
                temp = temp*num

                # 新字符串逐一入栈
                for i in temp:
                    stack.append(i)
                
        return ''.join(stack)

5、树

111. 二叉树的最小深度

题解1
官方题解

在这里插入图片描述

# 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 minDepth(self, root: TreeNode) -> int:
        if not root:
            return 0
        
        if (not root.left) and (not root.right):
            return 1
        
        min_depth = float('inf')
        if root.left:
            min_depth = min(self.minDepth(root.left), min_depth)
        if root.right:
            min_depth = min(self.minDepth(root.right), min_depth)
        
        return min_depth + 1

112. 路径总和

官方题解

在这里插入图片描述

# 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 hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:
            return False
        
        if (not root.left) and (not root.right):
            if root.val == targetSum:
                return True
            else:
                return False
        
        status_left = self.hasPathSum(root.left, targetSum - root.val)
        status_right = self.hasPathSum(root.right, targetSum - root.val)
        return status_left or status_right

173. 二叉搜索树迭代器

官方题解

在这里插入图片描述

# 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 BSTIterator:

    def __init__(self, root: TreeNode):
        self.data = []
        self.enqueue(root)
    
    def enqueue(self, node):
        while node:
            self.data.append(node)
            node = node.left

    def next(self) -> int:
        res = self.data.pop()
        self.enqueue(res.right)
        return res.val

    def hasNext(self) -> bool:
        return bool(self.data)


# Your BSTIterator object will be instantiated and called as such:
# obj = BSTIterator(root)
# param_1 = obj.next()
# param_2 = obj.hasNext()

6、位运算

231. 2 的幂

官方题解

在这里插入图片描述

class Solution:
    def isPowerOfTwo(self, n: int) -> bool:
        # method 1,自己的方法,效率更高效
        # while n > 1:
        #     if n%2 == 1:
        #         return False
        #     n = n>>1
        # return n == 1

        # method 2 n & (-n) = n
        return (n>0) and (n&-n==n)

78. 子集

官方题解

数组的每个元素,可以有两个状态:

  • 不在子数组中(用 000 表示);
  • 在子数组中(用 111 表示)。

从 0 到 2 的数组个数次幂(不包括)的整数的二进制表示就能表示所有状态的组合。

在这里插入图片描述

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        size = len(nums)
        n = 1 << size
        res = []

        for i in range(n):
            temp = []
            for j in range(size):
                if (i>>j) & 1:
                    temp.append(nums[j])
            res.append(temp)
        return res

137. 只出现一次的数字 II

官网题解,没看懂

137. 只出现一次的数字 II(有限状态自动机 + 位运算,清晰图解)
在这里插入图片描述

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        ones = 0
        twos = 0
        for num in nums:
            ones = ones^num & (~twos)
            twos = twos^num & (~ones)
        return ones

7、双指针

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

官方题解

在这里插入图片描述

# 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 (not head) or (head.next == None):
            return head
        cur = head

        while cur.next:
            if cur.val == cur.next.val:
                cur.next = cur.next.next
            else:
                cur = cur.next
        return head

141. 环形链表

官方题解

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

class Solution:
    def hasCycle(self, head: Optional[ListNode]) -> bool:
        # 快慢指针
        slow, fast = head, head
        
        # 循环内 bike 每次后移一个结点, car 每次后移 2 个结点
        # car 和 car->next 需要不为空,否则会发生非法内存访问
        # car 不为空,那么 bike 肯定也不为空
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                return True
        return False

148. 排序链表

在这里插入图片描述

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        
        # 合并两个有序链表
        def merge(head1: ListNode, head2: ListNode) -> ListNode:
            dummyHead = ListNode(0)
            temp, temp1, temp2 = dummyHead, head1, head2
            while temp1 and temp2:
                if temp1.val <= temp2.val:
                    temp.next = temp1
                    temp1 = temp1.next
                else:
                    temp.next = temp2
                    temp2 = temp2.next
                temp = temp.next
            if temp1:
                temp.next = temp1
            elif temp2:
                temp.next = temp2
            return dummyHead.next
        
        # 判断异常情况
        if not head:
            return head
        
        # 计算链表长度
        length = 0
        node = head
        while node:
            length += 1
            node = node.next
        
        dummyHead = ListNode(0, head)
        subLength = 1
        
        # 自底向上归并
        while subLength < length:
            prev, curr = dummyHead, dummyHead.next
            # 不停的分成两组,直到链表分组完成
            while curr:
                # 第1个待归并的链表
                head1 = curr
                for i in range(1, subLength):
                    if curr.next:
                        curr = curr.next
                    else:
                        break
                
                # 第2个待归并的链表
                head2 = curr.next
                curr.next = None
                curr = head2
                for i in range(1, subLength):
                    if curr and curr.next:
                        curr = curr.next
                    else:
                        break
                
                # 找到两个链表与后续的断点
                succ = None
                if curr:
                    succ = curr.next
                    curr.next = None
                
                # 合并两个有序链表
                merged = merge(head1, head2)
                prev.next = merged
                while prev.next:
                    prev = prev.next
                curr = succ
            
            # 子链表长度倍增
            subLength <<= 1
        
        return dummyHead.next

8、搜索

101. 对称二叉树

官方题解

在这里插入图片描述

# 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 isSymmetric(self, root: TreeNode) -> bool:
        def check(t1, t2):
            if (not t1) and (not t2):
                return True
            elif (not t1) or (not t2):
                return False
            else:
                return (t1.val==t2.val) and check(t1.left, t2.right) and check(t1.right, t2.left)
        
        return check(root, root)

94. 二叉树的中序遍历

官方题解

在这里插入图片描述

# 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: Optional[TreeNode]) -> List[int]:
        res = []
        def middle(cur):
            if not cur:
                return
            middle(cur.left)
            res.append(cur.val)
            middle(cur.right)
        middle(root)
        return res

230. 二叉搜索树中第K小的元素

官方题解

在这里插入图片描述

# 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 kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
        res = []
        while root or res:
            while root:
                res.append(root)
                root = root.left
            root = res.pop()
            k = k - 1
            if k == 0:
                return root.val
            root = root.right

我的思路:先进行中序遍历,然后返回第k个元素

# 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 kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
        res = []
        def mid(node):
            if not node:
                return
            mid(node.left)
            res.append(node.val)
            mid(node.right)
        mid(root)
        return res[k-1]

9、排序

977. 有序数组的平方

优秀题解
官方题解

在这里插入图片描述

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        size = len(nums)
        res = [0]*len(nums)
        index = size - 1
        left = 0
        right = size - 1
        while left <= right:
            s_left = nums[left]*nums[left]
            s_right = nums[right]*nums[right]
            if s_left >= s_right:
                res[index] = s_left
                left += 1
            else:
                res[index] = s_right
                right -= 1
            index -= 1
        return res

1122. 数组的相对排序

官方题解

在这里插入图片描述

class Solution:
    def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
        rank = {x:i for i,x in enumerate(arr2)}
        
        def my_sort(x):
            return (0, rank[x]) if x in rank else (1, x)
        arr1.sort(key=my_sort)
        return arr1

147. 对链表进行插入排序

官方题解

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def insertionSortList(self, head: ListNode) -> ListNode:
        dummpy = ListNode(0)
        dummpy.next = head

        last = head
        cur = head.next

        while cur:
            if last.val <= cur.val:
                last = last.next
            else:
                pred = dummpy
                while pred.next.val <= cur.val:
                    pred = pred.next
                last.next = cur.next
                cur.next = pred.next
                pred.next = cur
            cur = last.next
        
        return dummpy.next

10、动态规划

121. 买卖股票的最佳时机

官方题解

一次遍历

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        pmin = 1e5
        profit = 0
        for p in prices:
            profit = max(p-pmin, profit)
            pmin = min(p, pmin)
        return profit

动态规划
在这里插入图片描述

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        if n == 0:
            return 0
        
        minp = prices[0]
        profit = [0]*n
        for i in range(1, n):
            minp = min(prices[i], minp)
            profit[i] = max(prices[i]-minp, profit[i-1])
        return profit[-1]

122. 买卖股票的最佳时机 II

官方题解

贪心算法

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        res = 0
        for i in range(1, len(prices)):
            res += max(0, prices[i]-prices[i-1])
        return res

动态规划

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        profit = [[0]*2]*n
        profit[0][0] = 0
        profit[0][1] = -prices[0]

        for i in range(1, n):
            profit[i][0] = max(profit[i-1][0], profit[i-1][1]+prices[i])
            profit[i][1] = max(profit[i-1][1], profit[i-1][0]-prices[i])
        
        return profit[-1][0]

516. 最长回文子序列

官方题解

在这里插入图片描述

class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        n = len(s)
        res = [[0 for __ in range(n)] for _ in range(n)]

        # 为什么逆序?
        for i in range(n-1, -1, -1):
            res[i][i] = 1
            for j in range(i+1, n):
                if s[i]==s[j]:
                    res[i][j] = res[i+1][j-1] + 2
                else:
                    res[i][j] = max(res[i+1][j], res[i][j-1])
        return res[0][n-1]

11、分治

169. 多数元素

官方题解

排序后,返回中间值

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        nums.sort()
        return nums[len(nums)//2]

投票法

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        count = 0
        res = None

        for num in nums:
            if count == 0:
                res = num
            count += 1 if res==num else -1
        
        return res

53. 最大子数组和

官方题解

特别的动态规划

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        n = len(nums)
        if n < 1:
            return 0
        
        dp = [0 for i in range(n)]
        dp[0] = nums[0]

        for i in range(1, n):
            if dp[i-1] > 0:
                dp [i] = dp[i-1] + nums[i]
            else:
                dp[i] = nums[i]
        
        return max(dp)

105. 从前序与中序遍历序列构造二叉树

官方题解,好复杂
我更推荐看这位牛人的题解

递归方法

# 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 buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        if not (preorder and inorder):
            return None
        
        root = TreeNode(preorder[0])
        mid = inorder.index(preorder[0])
        root.left = self.buildTree(preorder[1:mid+1], inorder[0:mid])
        root.right = self.buildTree(preorder[mid+1:], inorder[mid+1:])
        return root

12. 哈希表

219. 存在重复元素 II

官方题解

在这里插入图片描述

class Solution:
    def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
        # 哈希法
        # pos = dict()        
        # for i, num in enumerate(nums):
        #     if num in pos and abs(i-pos[num])<=k:
        #         return True
        #     pos[num] = i
        # return False

        # 滑动窗口
        s = set()
        for i, num in enumerate(nums):
            if i > k:
                s.remove(nums[i-k-1])
            if num in s:
                return True
            s.add(num)
        return False

771. 宝石与石头

官方题解

在这里插入图片描述

class Solution:
    def numJewelsInStones(self, jewels: str, stones: str) -> int:
        res_map = dict()
        for j in jewels:
            res_map[j] = 0
        for s in stones:
            if s in res_map:
                res_map[s] += 1
        
        return sum(res_map.values())
class Solution:
    def numJewelsInStones(self, jewels: str, stones: str) -> int:
        js = set(jewels)
        return sum(s in js for s in stones)

811. 子域名访问计数

官方题解

在这里插入图片描述

class Solution:
    def subdomainVisits(self, cpdomains: List[str]) -> List[str]:
        res = dict()
        for item in cpdomains:
            tmp = item.split(' ')
            num = int(tmp[0])
            cpd = tmp[1].split('.')
            for i in range(len(cpd)):
                x = ".".join(cpd[i:])
                if x in res:
                    res[x] += num
                else:
                    res[x] = num
        
        return ["{} {}".format(v, k) for k, v in res.items()]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值