算法—合并区间

一、合并链表:2个升序链表合并成1个新的升序链表。

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

       1、迭代解法:

class Solution:
    def MergeTwoList(self, head1, head2):
        if not head1:
            return head2
        if not head2:
            return head1
        newhead = Node(None)
        p = newhead
        while head1 and head2:
            if head1.val>head2.val:
                p.next = head2.val #从小的开始串联
                head2 = head2.next #l2的头指针下移
            else:
                p.next = head1.val
                head1 = head1.next 
            p = p.next
        #继续串联
        if head1:
            p.next = head1
        if head2:
            p.next = head2
        return newhead.next         
   

        2、递归解法:

class Solution:
    def MergeTwoList(self, head1, head2):
        if not head1:
            return head2
        if not head2:
            return head1
        if head1.val>head2.val:
                #从小到大排,确定head2后,继续比较head1和 head2.next
                head2.next = self.MergeTwoList(head1, head2.next)
                return head2  #返回头节点。
            else:
                head1.next = self.MergeTwoList(head1.next, head2) 
                return head1

二、归并排序:

给出2个有序的整数数组,归并成新的有序数组。

思想:从尾部由大至小排序

class Solution:
    def MergeTwoArr(self, A, B):    
        if not A and not B:
            return []
        if not A:
            return B
        if not B:
            return A
        m, n = len(A)-1, len(B)-1
        #合并至数组A上,先扩展A的大小
        A.extend(B)
        while m>=0 and n>=0:
            if A[m] > B[n]:
                A[m+n+1] = A[m]
                m -= 1
            else:
                A[m+1+1] = B[n]
                n -= 1
        #考虑A合并完,B未合并完的情况;从大到小,直接将剩下的B放入A。
        if n >= 0:
            A[:n+1] = B[:n+1]
        return A
        

三、重排链表

给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:        给定链表 1->2->3->4, 重新排列为 1->4->2->3.
示例 2:        给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.

解法:先拆成2个链表,将后部链表反转,最后进行合并链表。

# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseNode(self, head)-> ListNode:
        if not head:
            return
        pre = None #记得末尾是None不是ListNode(None)
        p, q = head, head
        while p:
            q = p.next
            p.next = pre
            pre = p
            p = q
        return pre

    def reorderList(self, head: ListNode) -> None:
        """
        Do not return anything, modify head in-place instead.
        """
        if not head:
            return head
        pre, p = head, head
        #1、先根据中点拆成2个链表
        while p.next and p.next.next:
            pre = pre.next
            p = p.next.next
        #2、将后部的链表反转。
        if p.next: #偶数个节点,从中间节点后2位开始反转。
            p = pre.next.next
            pre.next.next = None
        else:      #奇数个节点,从中间节点后1位开始反转。 
            p = pre.next 
            pre.next = None
        #反转函数调用
        h2 = self.reverseNode(p)
        h1 = head 
        #3、进行2个链表的交叉合并
        while h1 and h2:
            tmp1 = h1.next
            h1.next = h2
            tmp2 = h2.next
            h2.next = tmp1
            h1, h2 = tmp1, tmp2
        return head

四、奇偶链表(leetcode.328)

给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。

请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。

示例 1:

输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL
示例 2:

输入: 2->1->3->5->6->4->7->NULL 
输出: 2->3->6->7->1->5->4->NULL
说明:

应当保持奇数节点和偶数节点的相对顺序。
链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。

思想:遍历的时候拆成2个链表,遍历完后再合并。

class Solution:
    def oddEvenList(self, head: ListNode) -> ListNode:
        if not head:
            return head
        pre = head
        p, q = head.next, head.next #q记录偶数节点链的头部
        while p and p.next: #以p开始,p走得快
            pre.next = p.next
            pre = pre.next  #奇数节点的连接
            p.next = pre.next #偶数节点的连接
            p = p.next  #交叉向后连接 
        pre.next = q
        return head

五、合并区间(leetcode.56.)

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。

示例 1:

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:

输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间

class Solution:
    #快排操作
    def partition(self, arr, left, right):
        if not arr:
            return
        if left >= right:
            return arr
        i, j = left, right
        base = arr[left]
        while i<j:
            while i<j and base[0] <= arr[j][0]:
                j -= 1
            arr[i] = arr[j]
            while i<j and base[0] >= arr[i][0]:
                i += 1
            arr[j] = arr[i]
        arr[i] = base
        self.partition(arr, left, i-1)
        self.partition(arr, i+1, right)
        return arr

    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        if not intervals:
            return intervals
        n = len(intervals)
        #1、对区间按区间头部进行排序——快排
        self.partition(intervals, 0, n-1)
        #2、在有序的前提下进行合并区间
        res = []
        sg = intervals[0]
        for i in range(1, n): #从第2个开始比较区间
            if intervals[i][0] > sg[1]: #区间独立,如[1,2][3,4]合并
                res.append(sg)
                sg = intervals[i]
            else:  #区间有重叠部分,需考虑[1,4][2,3]的情况-> [1,4]
                right = max(sg[1], intervals[i][1])
                left = min(sg[0], intervals[i][0]) 
                sg = [left, right]     
        res.append(sg)
        return res

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值