leetcode-分冶法/递归

归并排序

一个数组分成左右两部分,左边排好序,右边排好序,再做一个两个有序数组的合并

23. 合并K个升序链表

对数组归并

冒泡快排归并堆排序_MaYingColdPlay的博客-CSDN博客

看方法2,方法2是和对数组归并排序一样的。不同的是有一个对两个链表排序。

题目描述

#合并k个升序链表
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution(object):
    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        if len(lists)==0:
            return 
        if len(lists)==1:
            return lists[0]
        mid=len(lists)//2
        left=self.mergeKLists(lists[:mid])
        right=self.mergeKLists(lists[mid:])
        return self.merge(left,right)
        # 合并两个有序链表	
    def merge(self,left,right):
        dummy=ListNode(0)
        tmp=dummy
        while left and right:
            if left.val<right.val:
                tmp.next=left
                left=left.next
            else:
                tmp.next=right
                right=right.next
            tmp=tmp.next
        if left:
            tmp.next=left
        if right:
            tmp.next=right
        return dummy.next

148.排序链表

常规的快排和归并是对数组进行排序,这个题是对链表进行排序。

(快速排序,归并排序)

LeetCode 148——排序链表 - seniusen - 博客园

为什么要用归并排序。

[LeetCode] 148. Sort List 链表排序 - Grandyang - 博客园

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
 
class Solution(object):
    def sortList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if head is None or head.next is None:
            return head
        #左边
        left=head
        #终点
        mid=self.getmid(head)
        #右边
        right=mid.next
        mid.next=None
        #递归
        return self.merge(self.sortList(left),self.sortList(right))
    
    def merge(self,left,right):
        dummy=ListNode(0)
        tmp=dummy
        while left and right:
            if left.val<right.val:
                tmp.next=left
                left=left.next
            else:
                tmp.next=right
                right=right.next
            tmp=tmp.next
        if left:
            tmp.next=left
        if right:
            tmp.next=right
        return dummy.next
    #快慢指针找中点
    def getmid(self,node):
        if node is None:
            return None
        fast=slow=node
        while fast.next and fast.next.next:
            fast,slow=fast.next.next,slow.next
        return slow

剑指offer51- 数组中的逆序对

https://sbaban.com/jzo51.html

冒泡快排归并堆排序_MaYingColdPlay的博客-CSDN博客

对数组归并这个代码是从左到右遍历的,而逆序对得从右往左遍历,方便求count。

class Solution(object):
    def __init__(self):
        self.count=0
    def reversePairs(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        self.mergesort(nums)
        return self.count
    def mergesort(self,nums):
        if len(nums)<=1:
            return nums
        mid=len(nums)//2
        left=self.mergesort(nums[:mid])
        right=self.mergesort(nums[mid:])
        return self.merge(left,right)
    def merge(self,left,right):
        #从小到大
        result=[]
        i=len(left)-1
        j=len(right)-1
        while i >=0 and j >=0:
            if left[i]>right[j]:
                self.count=self.count+j+1
                result.insert(0,left[i])
                i=i-1
            elif left[i]<right[j]:
                result.insert(0,right[j])
                j=j-1
        result=left[:i+1]+result
        result=right[:j+1]+result
        print(result)
        return result

二刷

left[i]>right[j]

#从小到大排列,

#由于分冶之后数组是有序的,若left[i]>right[j],则[i,n]的数字都比right[j]大

这种方法可以过,但是没法确定num[i]后面比它小的逆序对有多少,因为在算的时候,是根据若left[i]>right[j],则[i,n]的数字都比right[j]大

力扣

class Solution(object):
    def __init__(self):
        self.count=0
    def reversePairs(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        self.mergesort(nums)
        return self.count
    def mergesort(self,nums):
        if len(nums)<=1:
            return nums
        mid=len(nums)//2
        left=self.mergesort(nums[:mid])
        right=self.mergesort(nums[mid:])
        return self.merge(left,right)
    def merge(self,left,right):
        #从小到大排列,
        #由于分冶之后数组是有序的,若left[i]>right[j],则[i,n]的数字都比right[j]大.
        #当left[i]>right[j]时,j+=1 ,所以不会造成重复计算
        #分冶合并的时候,把数组分为一块一块的,1和2合并之后为3,3内部不会再进行比较。所以只会产出一次比较,不会造成重复计算。
        result=[]
        i=0
        j=0
        while i<len(left) and j<len(right):
            if left[i]<=right[j]:
                result.append(left[i])
                i+=1
            else:
                result.append(right[j])
                self.count+=len(left)-i
                j+=1
        if i<len(left):
            result+=left[i:]
        if j<len(right):
            result+=right[j:]
        return result

left[i]<=right[j]

left[i]<=right[j]时,可以确定在right数组中,[0,j-1]都是比left[i]小的。

可以唯一确定nums[i]后面的逆序对有多少个。可以用这个思路继续做

315. 计算右侧小于当前元素的个数 

(315应该要引入一个索引数组,没有索引数组的话直接排元素,找不到数组快之间的先后位置)

注意在最后加上

 if i<len(left):
            result+=left[i:]
        while i<len(left):
            self.count += j
            i+=1

例子是

left=[4,5]

right=[2,3]

left有几个元素,就要加上j几次。

class Solution(object):
    def __init__(self):
        self.count=0
    def reversePairs(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        self.mergesort(nums)
        return self.count
    def mergesort(self,nums):
        if len(nums)<=1:
            return nums
        mid=len(nums)//2
        left=self.mergesort(nums[:mid])
        right=self.mergesort(nums[mid:])
        return self.merge(left,right)
    def merge(self,left,right):
        #从小到大排列,
        #left[i]<=right[j]时,可以确定在right数组中,[0,j-1]都是比left[i]小的。
        result=[]
        i=0
        j=0
        while i<len(left) and j<len(right):
            if left[i]<=right[j]:
                result.append(left[i])
                self.count+=j
                i+=1
            else:
                result.append(right[j])
                j+=1
        if i<len(left):
            result+=left[i:]
        while i<len(left):
            self.count += j
            i+=1
        if j<len(right):
            result+=right[j:]
        return result

315. 计算右侧小于当前元素的个数

一定要用一个索引数组,不然有重复值区分不出来。

class Solution(object):
    def countSmaller(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        arr = []
        res = [0] * len(nums)
        for idx, num in enumerate(nums):
            arr.append((idx, num))
        def merge_sort(arr):
            if len(arr) <= 1:
                return arr
            mid = len(arr) // 2
            left = merge_sort(arr[:mid])
            right = merge_sort(arr[mid:])
            # print(left, right)
            return merge(left, right)
        def merge(left, right):
            result = []
            i = 0
            j = 0
            while i < len(left) and j < len(right):
                if left[i][1] <= right[j][1]:
                    result.append(left[i])
                    res[left[i][0]] += j
                    i += 1
                else:
                    result.append(right[j])
                    j += 1
            if i < len(left):
                result += left[i:]
            while i < len(left):
                res[left[i][0]] += j
                i += 1
            if j < len(right):
                result += right[j:]
            return result

        merge_sort(arr)
        return res

快速排序

快速排序 - python版超详细讲解_Vince Li的博客-CSDN博客

215. 数组中的第K个最大元素

(也可堆排序)

在最开始要做个处理,k=len(nums)-k,第k大的元素,从最小位开始数是len(nums)-k个。然后就是快排的思想了。

class Solution(object):
    def __init__(self):
        self.res=0
    def quick_sort(self,alist,start,end,k):
        mid = alist[start]
        low=start
        high=end
        while low<high:
            while low<high and alist[high]>=mid:
                high=high-1
            alist[low]=alist[high]
            while low<high and alist[low]<mid:
                low=low+1
            alist[high]=alist[low]
        alist[low]=mid
        print(low)
        if low<k:
            #右边
            self.quick_sort(alist,low+1,end,k)
        elif low>k:
            self.quick_sort(alist,start,low-1,k)
        else:
            self.res=mid
            print(alist)
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        k=len(nums)-k
        self.quick_sort(nums,0,len(nums)-1,k)
        return self.res

优化解法

选择基准謉时候随机化,无序数组的话无差别,但是那种 奇怪的测试用例,比如 98111109 这种 有连续值了,随机打乱一下会好点。

class Solution(object):
    def __init__(self):
        self.res=0
    def quick_sort(self,alist,start,end,k):
        index = random.randint(start, end)
        # mid = alist[start]
        low=start
        high=end
        alist[low], alist[index] = alist[index], alist[low]
        mid=alist[start]
        while low<high:
            while low<high and alist[high]>=mid:
                high=high-1
            alist[low]=alist[high]
            while low<high and alist[low]<mid:
                low=low+1
            alist[high]=alist[low]
        alist[low]=mid
        if low<k:
            #右边
            self.quick_sort(alist,low+1,end,k)
        elif low>k:
            self.quick_sort(alist,start,low-1,k)
        else:
            self.res=mid
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        k=len(nums)-k
        self.quick_sort(nums,0,len(nums)-1,k)
        return self.res

4.寻找两个正序数组的中位数

等价于找第k小元素

 

 

 

 

class Solution(object):
    def findMedianSortedArrays(self, nums1, nums2):
        total = len(nums1) + len(nums2)
        # 如果A数组长度+B数组长度total是奇数,则找total/2+1小的元素
        # 即为中位数
        if total % 2 == 1:
            midIndex = total / 2 + 1
            res = self.getKthElement(nums1, nums2, midIndex)
            return float(res)
        # 否则,找total/2,total/2+1这两个元素    
        else:
            midIndex_1 = total / 2
            midIndex_2 = total / 2 + 1
            a = self.getKthElement(nums1, nums2, midIndex_1)
            b = self.getKthElement(nums1, nums2, midIndex_2)
            return (a + b) / 2.0

    def getKthElement(self,nums1, nums2, k):
        len1 = len(nums1)
        len2 = len(nums2)
        index1 = 0
        index2 = 0
        while True:
            # 边界情况,当index1越界时,直接返回nums2的第k小元素
            if index1 == len1:
                return nums2[index2 + k -1]
            # 边界情况,当index2越界时,直接返回nums1的第k小元素
            if index2 == len2:
                return nums1[index1 + k - 1]
            # 边界情况,k等于1时,返回nums1第一个元素和nums2第一个元素较小者
            if k == 1:
                return min(nums1[index1], nums2[index2])
            new_index1 = min(index1 + k / 2, len1) - 1 
            new_index2 = min(index2 + k / 2, len2) - 1
            pivot1 = nums1[new_index1]
            pivot2 = nums2[new_index2]
            # 比较nums1[k/2-1]和nums2[k/2-1]
            # 如果nums1的小,则忽略掉nums1[0] - nums1[k/2-1]这些元素
            # 再更新 k,k 要减去忽略掉的那些元素,index1也要更新,待下轮使用
            if pivot1 <= pivot2:
                k -= (new_index1 - index1 + 1)
                index1 = new_index1 + 1
            # 如果nums2的小,则忽略掉nums2[0] - nums2[k/2-1]这些元素
            # 再更新 k,k 要减去忽略掉的那些元素,index2也要更新,待下轮使用
            else:
                k -= (new_index2 - index2 + 1)
                index2 = new_index2 + 1

作者:wang_ni_ma
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/duo-tu-xiang-jie-liang-chong-shi-xian-by-75f4/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

75. 颜色分类

从3sum开始-双指针_林冲风雪山神庙的博客-CSDN博客

https://blog.csdn.net/weixin_39853245/article/details/95940448?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-9.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-9.channel_param 

241. 为运算表达式设计优先级

 

class Solution:
    def diffWaysToCompute(self, input: str) -> List[int]:
        # 如果只有数字,直接返回
        if input.isdigit():
            return [int(input)]

        res = []
        for i, char in enumerate(input):
            if char in ['+', '-', '*']:
                # 1.分解:遇到运算符,计算左右两侧的结果集
                # 2.解决:diffWaysToCompute 递归函数求出子问题的解
                left = self.diffWaysToCompute(input[:i])
                right = self.diffWaysToCompute(input[i+1:])
                # 3.合并:根据运算符合并子问题的解
                for l in left:
                    for r in right:
                        if char == '+':
                            res.append(l + r)
                        elif char == '-':
                            res.append(l - r)
                        else:
                            res.append(l * r)

        return res

作者:jalan
链接:https://leetcode-cn.com/problems/different-ways-to-add-parentheses/solution/pythongolang-fen-zhi-suan-fa-by-jalan/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值