leetcode 二分、分治

博客围绕LeetCode题目展开,涉及二分法在leetcode35、34、33题中的应用,介绍不同解题思路与效率。还阐述归并排序思想,其时间复杂度为O(NlogN),并运用归并排序解决leetcode315题及合并k个排序链表问题,分析了相关算法复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、leetcode35 二分,很简单

class Solution(object):
    def searchInsert(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        l = len(nums)
        start = 0
        end = l-1
        while start<=end:
            mid = int((start+end)/2)
            if target > nums[mid]:
                start = mid+1
            elif target< nums[mid]:
                end = mid-1
            elif target == nums[mid]:
                return mid
        nums.insert(start,target)
        return start

2、leetcode34

class Solution(object):
    def searchRange(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        start = 0
        end = len(nums)-1
        self.res = [end+1,-1]
        self.helper(nums,start,end,target)
        if self.res[0] == end+1 and self.res[1]==-1:
            return [-1,-1]
        return self.res
    def helper(self,nums,start,end,target):
        if start > end:
            return False
        mid = int((start+end)/2)
        if target > nums[mid]:
            self.helper(nums,mid+1,end,target)
        elif target < nums[mid]:
            self.helper(nums,start,mid-1,target)
        elif target == nums[mid]:
            if mid < self.res[0] : 
                self.res[0]= mid
            if mid >self.res[1]:
                self.res[1]= mid
            self.helper(nums,start,mid-1,target)                   
            self.helper(nums,mid+1,end,target)
                

我用的是纯递归+二分,看了评论可以写个遍历+递归,或者是通过写两个二分,通过找区间的左右端点来加快。

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        res=[-1,-1]
        res[0]=self.findleft(nums,0,len(nums)-1,target)
        res[1]=self.findright(nums,0,len(nums)-1,target)
        return res
    def findleft(self,nums,start,end,target):
        while start<=end:
            mid = int((start+end)/2)
            if target > nums[mid]:
                start = mid +1
            elif target < nums[mid]:
                end =mid-1
            elif target == nums[mid]:
                if mid ==0 or nums[mid-1]<target:
                    return mid
                else:
                    end = mid -1
        return -1
    def findright(self,nums,start,end,target):
        while start<=end:
            mid = int((start+end)/2)
            if target > nums[mid]:
                start = mid +1
            elif target < nums[mid]:
                end =mid-1
            elif target == nums[mid]:
                if mid ==len(nums)-1 or nums[mid+1]>target:
                    return mid
                else:
                    start = mid +1
        return -1
            

效率比较:
在这里插入图片描述3、leetcode33

class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        if len(nums)==0:
            return -1
        start = 0
        end = len(nums)-1
        if target>nums[end]:
            if target<nums[0]:
                    return -1
            for i in range(len(nums)-1):
                if target == nums[i]:
                    return i
                if nums[i]>nums[i+1]:
                    return -1
                    break
            return -1
        if target <nums[end]:
            i = end
            while i>=0:
                if target == nums[i]:
                    return i 
                if nums[i]<nums[i-1]:
                    return -1
                i -=1
            return -1
        if target == nums[end]:
            return end
            
            
        

用时居然击败了96%。。。。感觉就是暴力+一一点点分类,换了一种分前半部分和后半部分有序无序的二分方法写

class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        if len(nums)==0:
            return -1
        start = 0
        end = len(nums)-1
        while start<=end:
            mid = int((start+end)/2)
            if nums[mid]==nums[start]:
                for i in range(start,end+1):
                    if target == nums[i]:
                        return i
                return -1
            if nums[mid]<nums[start]: #前半部分无序,后半部分有序
                idx = self.findidx(nums,mid,end,target)
                print(idx)
                if idx!=-1:
                    return idx
                end = mid-1
            if nums[mid]>nums[start]:
                idx = self.findidx(nums,start,mid,target)
                if idx!=-1:
                    return idx
                start = mid 
        return -1

    def findidx(self,nums,start,end,target):
        while start<=end: 
            mid = int((start+end)/2)
            print(start,end,mid)
            if target == nums[mid]:
                return mid
            if target < nums[mid]:
                end = mid-1
            if target > nums[mid]:
                start = mid+1
        return -1

归并排序

class Solution(object):
    def countSmaller(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        self.mergesort(nums,0,len(nums)-1)
        return nums
    def mergesort(self,nums,start,end):
        if start<end:
            mid = int((start+end)/2)
            self.mergesort(nums,start,mid)
            self.mergesort(nums,mid+1,end)
            self.merge(nums,start,mid+1,end+1)
        else:
            return
    def merge(self,nums,start,mid,end):
        i = start
        j = mid
        s=[]
        while i < mid and j < end:
            #print(nums[i],nums[j])
            if nums[i]>nums[j]:
                s.append(nums[j])
                j +=1
            else:
                s.append(nums[i])
                i +=1
        while i <mid:
            s.append(nums[i])
            i +=1
        while j < end:
            s.append(nums[j])
            j +=1
        k=0
        for i in range(start,end): #更新从start到end区域的nums
            nums[i] = s[k]
            k+=1

归并排序的思想就是分治,将问题分解为多个相互独立、性质相同的子问题。时间复杂度为ONlogN,可根据这一思想解决一些问题。


4、leetcode315
给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。

示例:

输入: [5,2,6,1]
输出: [2,1,1,0]

class Solution(object):
    def countSmaller(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        self.count=[0 for i in range(len(nums))]
        res=[]
        for i in range(len(nums)):
            t = (nums[i],i)
            res.append(t)
        self.mergesort(res,0,len(nums)-1)
        return self.count
    def mergesort(self,nums,start,end):
        if start<end:
            mid = int((start+end)/2)
            self.mergesort(nums,start,mid)
            self.mergesort(nums,mid+1,end)
            self.merge(nums,start,mid+1,end+1)
        else:
            return
    def merge(self,nums,start,mid,end):
        i = start
        j = mid
        s=[]
        while i < mid and j < end:
            if nums[i]<=nums[j]:
                s.append(nums[i])
                self.count[nums[i][1]]+=j-mid
                i +=1
            else:
                s.append(nums[j])
                j +=1
        while i <mid:
            s.append(nums[i])
            self.count[nums[i][1]]+=j-mid
            i +=1
        while j < end:
            s.append(nums[j])
            j +=1
        #print(self.count)
        k=0
        for i in range(start,end):
            nums[i] = s[k]
            k+=1
  • 这个题用归并做的,思想是在归并中加入tuple(value,index),之后对tuple比较
  • 其中比较重要的merge函数的编写,merge函数最重要的是什么时候更新count,即当前一部分i列表的元素大于后一部分j列表元素时,此时j所指的位置之前所有的位置均小于当前i列表中元素,将j更新到count[i]中去。

5、合并 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 None
        if len(lists)==1:
            return lists[0]
        if len(lists) == 2:
            return self.merge(lists[0],lists[1])
        mid = int((len(lists)-1)/2)
        return self.merge(self.mergeKLists(lists[:mid+1]),self.mergeKLists(lists[mid+1:]))
    def merge(self,l1,l2):
        head = ListNode(-1)
        p = head
        while l1 and l2:
            if l1.val<=l2.val:
                head.next = l1
                head = head.next
                l1 = l1.next
            else:
                head.next = l2
                head = head.next
                l2 = l2.next
        if l1:
            head.next = l1
            head = head.next
            l1 = l1.next
        if l2:
            head.next = l2
            head = head.next
            l2 = l2.next
        return p.next
                 
                
            

用归并,复杂度O(logK*KN)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值