一、合并链表: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