【leetcode刷题之路】面试经典150题(7)——分治+Kadane 算法+二分查找+堆

文章目录

      • [16 分治](#16 分治)
        • [16.1 【分治】将有序数组转换为二叉搜索树](#16.1 【分治】将有序数组转换为二叉搜索树)
        • [16.2 【归并排序】排序链表](#16.2 【归并排序】排序链表)
        • [16.3 【分治】建立四叉树](#16.3 【分治】建立四叉树)
        • [16.4 【暴力】合并 K 个升序链表](#16.4 【暴力】合并 K 个升序链表)
      • [17 Kadane 算法](#17 Kadane 算法)
        • [17.1 【动态规划】最大子数组和](#17.1 【动态规划】最大子数组和)
        • [17.2 【动态规划】环形子数组的最大和](#17.2 【动态规划】环形子数组的最大和)
      • [18 二分查找](#18 二分查找)
        • [18.1 【二分】搜索插入位置](#18.1 【二分】搜索插入位置)
        • [18.2 【二分】搜索二维矩阵](#18.2 【二分】搜索二维矩阵)
        • [18.3 【二分】寻找峰值](#18.3 【二分】寻找峰值)
        • [18.4 【二分】搜索旋转排序数组](#18.4 【二分】搜索旋转排序数组)
        • [18.5 【二分】在排序数组中查找元素的第一个和最后一个位置](#18.5 【二分】在排序数组中查找元素的第一个和最后一个位置)
        • [18.6 【二分】寻找旋转排序数组中的最小值](#18.6 【二分】寻找旋转排序数组中的最小值)
        • [18.7 【二分】寻找两个正序数组的中位数](#18.7 【二分】寻找两个正序数组的中位数)
      • [19 堆](#19 堆)
        • [19.1 【二分】数组中的第K个最大元素](#19.1 【二分】数组中的第K个最大元素)
        • [19.2 【贪心】502. IPO](#19.2 【贪心】502. IPO)
        • [19.3 【优先队列】查找和最小的 K 对数字](#19.3 【优先队列】查找和最小的 K 对数字)

16 分治

16.1 【分治】将有序数组转换为二叉搜索树

题目地址:https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/description/?envType=study-plan-v2&envId=top-interview-150

详见代码。

python 复制代码
# 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 sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
        def divide(nums,left,right):
            if left > right:
                return None
            else:
                m = (left+right)//2
                root = TreeNode(nums[m])
                root.left = divide(nums,left,m-1)
                root.right = divide(nums,m+1,right)
                return root
        return divide(nums,0,len(nums)-1)
16.2 【归并排序】排序链表

题目地址:https://leetcode.cn/problems/sort-list/description/?envType=study-plan-v2&envId=top-interview-150

首先找到链表的中间位置,然后使用归并排序以此递归遍历链表。

python 复制代码
# 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]:
        if not head or not head.next:
            return head
        slow,fast = head,head.next
        while fast and fast.next:
            slow,fast = slow.next,fast.next.next
        mid = slow.next
        slow.next = None
        left,right = self.sortList(head),self.sortList(mid)
        h = ans = ListNode()
        while left and right:
            if left.val < right.val:
                h.next = left
                left = left.next
            else:
                h.next = right
                right = right.next
            h = h.next
        h.next = left if left else right
        return ans.next
16.3 【分治】建立四叉树

题目地址:https://leetcode.cn/problems/construct-quad-tree/description/?envType=study-plan-v2&envId=top-interview-150

首先需要判断每个方块中的数字是否是相同的,其次要找到递归的条件,这里的条件就是每个方块的四个组成部分,然后以此向内遍历,直到出现叶子结点就算结束。

python 复制代码
"""
# Definition for a QuadTree node.
class Node:
    def __init__(self, val, isLeaf, topLeft, topRight, bottomLeft, bottomRight):
        self.val = val
        self.isLeaf = isLeaf
        self.topLeft = topLeft
        self.topRight = topRight
        self.bottomLeft = bottomLeft
        self.bottomRight = bottomRight
"""

class Solution:
    def construct(self, grid: List[List[int]]) -> 'Node':
        # if current grid is leaf or not
        def is_grid(grid):
            l = len(grid)
            ssum = 0
            for i in range(l):
                ssum += sum(grid[i])
            if ssum == l*l:
                return True
            elif ssum == 0:
                return False
            else:
                return None
        
        grid_flag = is_grid(grid)
        l = len(grid)
        if grid_flag == True:
            node = Node(True,True,None,None,None,None)
        elif grid_flag == False:
            node = Node(False,True,None,None,None,None)
        else:
            m = l // 2
            topleft_grid = [[grid[i][j] for j in range(m)] for i in range(m)]
            topright_grid = [[grid[i][j] for j in range(m,l)] for i in range(m)]
            bottomleft_grid = [[grid[i][j] for j in range(m)] for i in range(m,l)]
            bottomright_grid = [[grid[i][j] for j in range(m,l)] for i in range(m,l)]
            node = Node(False,False,self.construct(topleft_grid),self.construct(topright_grid),
                        self.construct(bottomleft_grid),self.construct(bottomright_grid))
        return node
16.4 【暴力】合并 K 个升序链表

题目地址:https://leetcode.cn/problems/merge-k-sorted-lists/description/?envType=study-plan-v2&envId=top-interview-150

将链表两两合并。

python 复制代码
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next

class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        def merge(l1,l2):
            cur = tmp = ListNode()
            while l1 and l2:
                if l1.val < l2.val:
                    tmp.next = l1
                    l1 = l1.next
                else:
                    tmp.next = l2
                    l2 = l2.next
                tmp = tmp.next
            if l1:
                tmp.next = l1
            if l2:
                tmp.next = l2
            return cur.next
        
        ans = None
        for i in lists:
            ans = merge(ans,i)
        return ans

17 Kadane 算法

17.1 【动态规划】最大子数组和

题目地址:https://leetcode.cn/problems/maximum-subarray/description/?envType=study-plan-v2&envId=top-interview-150

利用动态规划,首先定义数组 d p [ i ] dp[i] dp[i],表示终点下标为i的序列的最大子数组和,主要考虑以下两种情况:

  • 如果 d p [ i − 1 ] dp[i-1] dp[i−1]大于 0 0 0,则继续向前增加下标为i的数值,作为 d p [ i ] dp[i] dp[i]的子数组和;
  • 如果 d p [ i − 1 ] dp[i-1] dp[i−1]小于 0 0 0,则从这里开始停止,重新计算子数组和,赋值为 0 0 0后再加入下标为i的数值,作为 d p [ i ] dp[i] dp[i]的子数组和。

最后的结果就是数组中最大的那个值。

python 复制代码
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        ans,dp = nums[0],nums[0]
        for i in range(1,len(nums)):
            dp = max(dp,0) + nums[i]
            if dp > ans:
                ans = dp
        return ans
17.2 【动态规划】环形子数组的最大和

题目地址:https://leetcode.cn/problems/maximum-sum-circular-subarray/description/?envType=study-plan-v2&envId=top-interview-150

分为两种情况,如果答案在数组中间,则是最大子数组和,如果答案在数组两边,则是数字的和减去最小子数组和。

python 复制代码
class Solution:
    def maxSubarraySumCircular(self, nums: List[int]) -> int:
        ans_max,dp_max = nums[0],nums[0]
        ans_min,dp_min = nums[0],nums[0]
        total = sum(nums)

        for i in range(1,len(nums)):
            dp_max = max(dp_max,0) + nums[i]
            if dp_max > ans_max:
                ans_max = dp_max
            dp_min = min(dp_min,0) + nums[i]
            if dp_min < ans_min:
                ans_min = dp_min
        
        if total - ans_min == 0:
            return ans_max
        else:
            return max(ans_max,total-ans_min)

18 二分查找

18.1 【二分】搜索插入位置

题目地址:https://leetcode.cn/problems/search-insert-position/description/?envType=study-plan-v2&envId=top-interview-150

二分查找,注意左右边界的取值。

python 复制代码
class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        left,right = 0,len(nums)-1
        while left <= right:
            m = (left+right)//2
            if target < nums[m]:
                right = m-1
            elif target > nums[m]:
                left = m+1
            else:
                return m
        return right+1
18.2 【二分】搜索二维矩阵

题目地址:https://leetcode.cn/problems/search-a-2d-matrix/?envType=study-plan-v2&envId=top-interview-150

双二分查找。

python 复制代码
class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        row,col = len(matrix),len(matrix[0])
        row_l,row_r = 0,row-1
        while row_l <= row_r:
            m = (row_l+row_r)//2
            if target < matrix[m][0]:
                row_r = m-1
            elif target > matrix[m][0]:
                row_l = m+1
            elif target == matrix[m][0]:
                return True
        if row_r == 0 and matrix[row_r][0] > target:
            return False
        col_l,col_r = 0,col-1
        while col_l <= col_r:
            m = (col_l+col_r)//2
            if target < matrix[row_r][m]:
                col_r = m-1
            elif target > matrix[row_r][m]:
                col_l = m+1
            elif target == matrix[row_r][m]:
                return True
        return False
18.3 【二分】寻找峰值

题目地址:https://leetcode.cn/problems/find-peak-element/description/?envType=study-plan-v2&envId=top-interview-150

如果中间位置的值比左边大,那么在该索引的右边一定存在峰值;同理,如果中间位置的值比右边大,那么在该索引的左边一定存在峰值,最后注意中间索引的取值,避免出现循环。

python 复制代码
class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        l,r = 0,len(nums)-1
        while l < r:
            m = (l+r+1)//2
            if nums[m] > nums[m-1]:
                l = m
            else:
                r = m-1
        return l
18.4 【二分】搜索旋转排序数组

题目地址:https://leetcode.cn/problems/search-in-rotated-sorted-array/description/?envType=study-plan-v2&envId=top-interview-150

不管怎么进行旋转,数组都会被分为有序的两部分,每次进行二分前比较一下中间索引与左右边界的值,如果 n u m s [ m ] > = n u m s [ l e f t ] nums[m]>=nums[left] nums[m]>=nums[left],则索引左边有序,否则右边有序。

python 复制代码
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left,right = 0,len(nums)-1
        while left <= right:
            m = (left+right+1)//2
            if nums[m] == target:
                return m
            if nums[m] >= nums[left]:
                if nums[left] <= target < nums[m]:
                    right = m-1
                else:
                    left = m+1
            else:
                if nums[m] < target <= nums[right]:
                    left = m+1
                else:
                    right = m-1
        return -1
18.5 【二分】在排序数组中查找元素的第一个和最后一个位置

题目地址:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/description/?envType=study-plan-v2&envId=top-interview-150

两次二分,第一次找出第一个位置,第二次找到 t a r g e t + 1 target+1 target+1的第一个位置,该位置左边就是 t a r g e t target target最后一个位置。

python 复制代码
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def bin_sort(left,right,tgt):
            while left <= right:
                m = (left+right+1)//2
                if nums[m] < tgt:
                    left = m+1
                else:
                    right = m-1
            return left
        
        first = bin_sort(0,len(nums)-1,target)
        if first == len(nums) or nums[first]!=target:
            return [-1,-1]
        else:
            last = bin_sort(0,len(nums)-1,target+1) - 1
            return [first,last]
18.6 【二分】寻找旋转排序数组中的最小值

题目地址:https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/description/?envType=study-plan-v2&envId=top-interview-150

详见代码。

python 复制代码
class Solution:
    def findMin(self, nums: List[int]) -> int:
        left,right = 0,len(nums)-1
        while left <= right:
            m = (left+right+1)//2
            if nums[m] < nums[0]:
                right = m-1
            else:
                left = m+1
        if left == len(nums):
            return nums[0]
        else:
            return nums[left]
18.7 【二分】寻找两个正序数组的中位数

题目地址:https://leetcode.cn/problems/median-of-two-sorted-arrays/description/?envType=study-plan-v2&envId=top-interview-150

如果数组的总长度是奇数,那么中位数就是第 m + n + 1 2 \frac{m+n+1}{2} 2m+n+1小的元素;如果数组的总长度是偶数,那么中位数就是第 m + n + 1 2 \frac{m+n+1}{2} 2m+n+1和第 m + n + 2 2 \frac{m+n+2}{2} 2m+n+2小的元素的平均值。

函数get_k_min是一个辅助函数,它用于找到两个已排序数组的第 k k k小的数。它通过比较两个数组的第 k / 2 k/2 k/2个元素来实现这个功能。如果数组 1 1 1的第 k / 2 k/2 k/2个元素小于数组 2 2 2的第 k / 2 k/2 k/2个元素,那么数组 1 1 1的前 k / 2 k/2 k/2个元素一定不会是第 k k k小的数,所以可以将它们排除在外。反之亦然。这个过程会一直持续到 k k k等于 1 1 1或者其中一个数组为空。

python 复制代码
class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        def k_min(start1,end1,start2,end2,k):
            cur_nums1 = end1-start1+1
            cur_nums2 = end2-start2+1
            if cur_nums1 == 0:
                return nums2[start2+k-1]
            if cur_nums2 == 0:
                return nums1[start1+k-1]
            if k == 1:
                return min(nums1[start1],nums2[start2])
            m1 = start1 + min(cur_nums1,k//2) - 1
            m2 = start2 + min(cur_nums2,k//2) - 1
            if nums1[m1] <= nums2[m2]:
                return k_min(m1+1,end1,start2,end2,k-(m1-start1+1))
            else:
                return k_min(start1,end1,m2+1,end2,k-(m2-start2+1))
        m,n = len(nums1),len(nums2)
        a,b = (m+n+1)//2,(m+n+2)//2
        x = k_min(0,m-1,0,n-1,a)
        y = k_min(0,m-1,0,n-1,b)
        return (x+y)/2

19 堆

19.1 【二分】数组中的第K个最大元素

题目地址:https://leetcode.cn/problems/kth-largest-element-in-an-array/description/?envType=study-plan-v2&envId=top-interview-150

详见代码。

python 复制代码
#方法一
class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        def quick_sort(num,k):
            big,equal,small = [],[],[]
            for n in num:
                if n > num[0]:
                    big.append(n)
                elif n < num[0]:
                    small.append(n)
                else:
                    equal.append(n)
            if k <= len(big):
                return quick_sort(big,k)
            elif k > len(equal) + len(big):
                return quick_sort(small,k-len(equal)-len(big))
            else:
                return num[0]
        return quick_sort(nums,k)
#方法二
class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        nums.sort()
        l = len(nums)
        return nums[l-k]
19.2 【贪心】502. IPO

题目地址:https://leetcode.cn/problems/ipo/description/?envType=study-plan-v2&envId=top-interview-150

在当前的本金小于等于当前资本的项目中,每次都选择利益最大的那个,但要注意特殊情况,当前的本金已经不能投资任何项目时,直接结束。

python 复制代码
class Solution:
    def findMaximizedCapital(self, k: int, w: int, profits: List[int], capital: List[int]) -> int:
        pro_cap = sorted(zip(profits,capital),key = lambda x:x[1])
        idx,l = 0,len(profits)
        cur = []
        while k:
            while idx < l and pro_cap[idx][1] <= w:
                heapq.heappush(cur,-pro_cap[idx][0])
                idx += 1
            if cur:
                w -= heapq.heappop(cur)
            else:
                break
            k -= 1
        return w
19.3 【优先队列】查找和最小的 K 对数字

题目地址:https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/description/?envType=study-plan-v2&envId=top-interview-150

多路归并思想,每次将三元组(两数组之和,数组1下标idx1,数组2下标idx2)加入到优先队列中,以两个数组中较小长度的为数组1,较大长度的为数组2,每次将优先队列的栈顶出列(当前未被加入到答案的所有点对中的最小值),然后将下一组下标加入优先队列中。

python 复制代码
class Solution:
    def kSmallestPairs(self, nums1: List[int], nums2: List[int], k: int) -> List[List[int]]:
        flag = True
        if len(nums1) > len(nums2):
            nums1,nums2 = nums2,nums1
            flag = False
        n1,n2 = len(nums1),len(nums2)
        ans,pq = [],[]
        for i in range(min(n1,k)):
            heapq.heappush(pq,(nums1[i]+nums2[0],i,0))
        while len(ans) < k:
            _,idx1,idx2 = heapq.heappop(pq)
            if flag:
                ans.append([nums1[idx1],nums2[idx2]])
            else:
                ans.append([nums2[idx2],nums1[idx1]])
            if idx2+1 < n2:
                heapq.heappush(pq,(nums1[idx1]+nums2[idx2+1],idx1,idx2+1))
        return ans
(nums2)
        ans,pq = [],[]
        for i in range(min(n1,k)):
            heapq.heappush(pq,(nums1[i]+nums2[0],i,0))
        while len(ans) < k:
            _,idx1,idx2 = heapq.heappop(pq)
            if flag:
                ans.append([nums1[idx1],nums2[idx2]])
            else:
                ans.append([nums2[idx2],nums1[idx1]])
            if idx2+1 < n2:
                heapq.heappush(pq,(nums1[idx1]+nums2[idx2+1],idx1,idx2+1))
        return ans
相关推荐
林开落L11 分钟前
前缀和算法习题篇(上)
c++·算法·leetcode
远望清一色12 分钟前
基于MATLAB边缘检测博文
开发语言·算法·matlab
tyler_download13 分钟前
手撸 chatgpt 大模型:简述 LLM 的架构,算法和训练流程
算法·chatgpt
SoraLuna34 分钟前
「Mac玩转仓颉内测版7」入门篇7 - Cangjie控制结构(下)
算法·macos·动态规划·cangjie
我狠狠地刷刷刷刷刷37 分钟前
中文分词模拟器
开发语言·python·算法
鸽鸽程序猿37 分钟前
【算法】【优选算法】前缀和(上)
java·算法·前缀和
九圣残炎43 分钟前
【从零开始的LeetCode-算法】2559. 统计范围内的元音字符串数
java·算法·leetcode
YSRM1 小时前
Experimental Analysis of Dedicated GPU in Virtual Framework using vGPU 论文分析
算法·gpu算力·vgpu·pci直通
韭菜盖饭1 小时前
LeetCode每日一题3261---统计满足 K 约束的子字符串数量 II
数据结构·算法·leetcode
xxxmmc1 小时前
Leetcode 75 Sort colors
leetcode·三指针移动问题