LeetCode刷题之《错题集》

剑指Offer11-旋转数组的最小数字

输入:[3,4,5,1,2]
输出:1

class Solution:
    def minArray(self, numbers: List[int]) -> int:
        # 方法1:无论如何旋转,最小值不变
        return min(numbers)

        # 方法2:顺序查找,找到最小值
        minNum = numbers[0]
        for i in range(1, len(numbers)):
            if numbers[i] < minNum:
                minNum = numbers[i]
        return minNum

        # 方法3:二分查找
        low = 0
        high = len(numbers) - 1
        while low < high:
            mid = low + (high-low)//2
            if numbers[mid] < numbers[high]:
                high = mid
            elif numbers[mid] > numbers[high]:
                low = mid + 1
            else:
                high -= 1
        return numbers[low]
189-旋转数组

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右旋转 1 步: [7,1,2,3,4,5,6]
向右旋转 2 步: [6,7,1,2,3,4,5]
向右旋转 3 步: [5,6,7,1,2,3,4]

  • 方法1:使用辅助数组
class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        # 方法1
        res = []
        length = len(nums)
        key = length - (k % length)    # 关键取余数操作
        for i in range(key,length,1):
            res.append(nums[i])
        for j in range(key):
            res.append(nums[j])
        nums[:] = res

        # 方法2
        res = []
        length = len(nums)
        key = length - (k % length) 
        res = nums[key:] + nums[:key]
        nums[:] = res
  • 方法2:原地交换

剑指Offer53-在排序数组中查找数字

输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
解释: 8在排序数组中出现了2次

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        # 方法1:顺序查找
        # res = 0
        # for num in nums:
        #     if num == target:
        #         res += 1
        # return res

        # 方法2:二分查找
        # 1 搜索右边界,右边界的左侧都是 <= target 的数
        left = 0
        right = len(nums) - 1
        while left <= right:
            mid = left + (right-left)//2
            if nums[mid] > target:
                right = mid - 1
            else:
                left = mid + 1
        rightNum = left

        # 如果数组中没有target,则提前返回
        if right >= 0 and nums[right] != target:
            return 0
        
        # 2 搜索左边界
        left = 0
        right = len(nums) - 1
        while left <= right:
            mid = left + (right-left)//2
            if nums[mid] < target:
                left = mid + 1
            else:
                right = mid - 1
        leftNum = right

        return rightNum - leftNum - 1
566-重塑数组

输入:mat = [[1,2],[3,4]], r = 1, c = 4
输出:[[1,2,3,4]]

  • 寻找映射关系
    # 映射关系:
    # 行:r = i//col 取整数
    # 列:c = i % col 取余数
class Solution:
    def matrixReshape(self, mat: List[List[int]], r: int, c: int) -> List[List[int]]:
        row = len(mat)
        col = len(mat[0])
        if row*col != r*c:
            return mat
        res = [[0 for i in range(c)] for j in range(r)]
        for i in range(row*col):
            res[i//c][i%c] = mat[i//col][i%col]
        return res
3-无重复字符的最长子串

输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

  • 动态规划+哈希表
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        hashMap = {}
        left = 0
        maxLen = 0
        for index, val in enumerate(s):
            if val in hashMap:
                left = max(left, hashMap[val]+1)
            hashMap[val] = index
            maxLen = max(maxLen, index-left+1)
        return maxLen
21-合并两个有序的链表

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

  • 方法1:使用递归
    递归表达式——总结出子问题
    情况1: list1[0] + merge(list[1:], list2[0]) if list1[0] < list2[0]
    情况2: list2[0] + merge(list[0], list2[1:]) if list1[0] >= list2[0]
    特别情况:当l1 或者 l2 是空链表
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        if l1 is None:
            return l2
        elif l2 is None:
            return l1
        elif l1.val < l2.val:      # 先连上较小的数
            l1.next = self.mergeTwoLists(l1.next, l2)
            return l1
        elif l1.val >= l2.val:
            l2.next = self.mergeTwoLists(l1, l2.next)
            return l2
  • 方法2:使用迭代
    思路:当l1和l2都不是空链表时,判断l1和l2哪一个链表的头结点的值更小,将较小值的节点添加到结果里面,当一个节点被添加到结果里面之后,将对应链表中的节点向后移动一位
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:

        # 定义一个新的链表
        prehead = ListNode(-1)
        prev = prehead

        while l1 and l2:             # 终止条件:都不为空
            if l1.val <= l2.val:
                prev.next = l1
                l1 = l1.next
            else:
                prev.next = l2
                l2 = l2.next
            prev = prev.next
        # 合并之后l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并的链表即可
        prev.next = l1 if l1 is not None else l2
        return prehead.next
19-删除链表的倒数第n个结点

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

  • 方法1:使用双指针
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        # 双指针
        dummy = ListNode(0,head)     # 哑结点
        slow = dummy
        fast = head
        for i in range(n):           # slow和fast中间相隔两个 n 个结点
            fast = fast.next
        
        while fast is not None:      # 当fast到达末尾,slow所指的下一个节点将被删除
            slow = slow.next
            fast = fast.next
        
        # 删除节点元素
        slow.next = slow.next.next   
        
        return dummy.next

你可能感兴趣的:(LeetCode刷题之《错题集》)