已知头指针分别为la和Ib的带头结点的
单链表中,结点按元素值非递减有序排列。写出将
la和Ib两链表归并成一个结点按元素值非递减有序排
列的单链表(其头指针为Ic),并计算算法的时间复
杂度。
归并排序,o(n)。实现懒得写,自己查
编写回溯算法代码时,要先考虑这个问题是一个什么搜索树,然后套用那个搜索树模板就行了。(例如:子集树就是:判断是否满足约束条件——计算、x[i]=1——递归左子树——归还——x[i]=0、递归右子树(注意限界思想))
(例如:排列树就是:循环——判断是否满足约束条件——交换——计算——递归(注意限界思想)——归还)
当然具体算法要具体分析
还要注意及时更新解和存储解,别忘了进入右子树、循环结束前,要将你算的、交换过的东西,要归还回去。注意到达叶结点干什么,没有到达怎么做
而分支限界算法的代码编写,首先编写三个类:活结点类、活结点属性类、入队类。然后选择好什么样的队列方式。一定要考虑好属性,然后什么时候添加结点、以及出队、和存储最优解
两个算法编写,还要注意限界函数的设置,怎么设计一个好的代价函数可以裁掉更多的空间。这就是两个算法的优化思想。
当然最重要的还要考虑好约束条件。
具体逻辑代码还是多写多练。多去总结。这里也就只讲个大体思路。
# 定义一个单链表节点类
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
# 定义合并两个单链表的函数
def mergeTwoLists(l1: ListNode, l2: ListNode) -> ListNode:
# 定义虚拟头指针
dummy = ListNode(0)
# 定义指针p指向虚拟头指针
p = dummy
# 当两个链表都不为空时进行循环
while l1 and l2:
# 如果l1的值更小,则将p的next指向l1,并将l1指针向后移一位
if l1.val <= l2.val:
p.next = l1
l1 = l1.next
# 如果l2的值更小,则将p的next指向l2,并将l2指针向后移一位
else:
p.next = l2
l2 = l2.next
# 将p指针向后移一位
p = p.next
# 如果l1不为空,则将p的next指向l1
if l1:
p.next = l1
# 如果l2不为空,则将p的next指向l2
else:
p.next = l2
# 返回虚拟头指针的next指针,即为合并后的新链表的头指针
return dummy.next
# 定义合并两个单链表的函数,时间复杂度O(min(m,n))
def mergeTwoLists(la: ListNode, lb: ListNode) -> ListNode:
# 取两个链表的第一个节点
pa, pb = la.next, lb.next
# 如果其中一个链表为空,则直接返回另一个链表
if not pa:
return lb
elif not pb:
return la
# 如果两个链表都不为空,比较第一个节点的大小
if pa.val < pb.val:
# 如果la的第一个节点更小,则先将la的第一个节点记为头结点
pc = la
pa = pa.next
else:
# 如果lb的第一个节点更小,则先将lb的第一个节点记为头结点
pc = lb
pb = pb.next
# pt指向新链表的最后一个节点,初始时为pc
pt = pc
while pa and pb:
# 如果la的当前节点更小,则将当前节点加入到新链表的尾部
if pa.val < pb.val:
pt.next = pa
pa = pa.next
# 如果lb的当前节点更小,则将当前节点加入到新链表的尾部
else:
pt.next = pb
pb = pb.next
# 将pt指向新链表的最后一个节点
pt = pt.next
# 如果la还有剩余节点,则将剩余节点挂到新链表的尾部
if pa:
pt.next = pa
# 如果lb还有剩余节点,则将剩余节点挂到新链表的尾部
else:
pt.next = pb
# 返回新链表的头结点
return pc.next
# 调用函数,将两个单链表按元素值非递减有序排列合并成一个新的单链表
la = ListNode(0, ListNode(1, ListNode(3, ListNode(5))))
lb = ListNode(0, ListNode(2, ListNode(4, ListNode(6))))
lc = mergeTwoLists(la, lb)
# 输出新的单链表
while lc:
print(lc.val, end=' ')
lc = lc.next
# 时间复杂度O(m+n),其中m、n分别为两个链表的长度
注:以上代码中都采用的是后插法,时间复杂度O(m+n),其中m、n分别为两个链表的长度。代码段落1采用的是递归法,代码量更少,但是时间复杂度和空间复杂度均为O(m+n),可能会出现栈溢出的问题。如果链表过长,建议使用代码段落2中的方法,时间复杂度更低。