排序链表
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
解法
首先是O(nlogn)的时间复杂度,所以想到快速排序和归并排序,但是快速排序最坏情况下是n^2的,所以用归并,而且对于链表来说使用归并排序占用空间为O(1)。
链表和数组最大的不同就是链表需要从前往后一个个找,而且要注意指针的问题,不要被覆盖,以及随时判断为none的情况。
链表获取中间值的方式比较有意思。
# 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 == None or head.next == None:
return head
mid = self.getmid(head)
l = head
r = mid.next
mid.next = None
return self.merge(self.sortList(l), self.sortList(r))
def merge(self, l, r):
root = ListNode(0)
tmp = root
curl, curr = l, r
while curl != None and curr != None:
if curl.val < curr.val:
tmp.next = curl
curl = curl.next
else:
tmp.next = curr
curr = curr.next
tmp = tmp.next
if curl != None:
tmp.next = curl
if curr != None:
tmp.next = curr
return root.next
def getmid(self, node):
if node == None:
return node
fast = slow = node
while fast.next != None and fast.next.next != None:
slow = slow.next
fast = fast.next.next
return slow
环形链表
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
进阶:
你能用 O(1)(即,常量)内存解决此问题吗?
解法
判断单链表是否有环的经典问题。类似于求中值一样,设置两个指针,快指针每次步长是2,慢指针步长为1,如果有环,两个必定相遇。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def hasCycle(self, head):
"""
:type head: ListNode
:rtype: bool
"""
if head == None:
return False
fast = slow = head
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
if fast == slow:
return True
return False
相交链表
编写一个程序,找到两个单链表相交的起始节点。
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
注意:
如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存
解法
有两种方法:
- 把B链表接在A链表后面,如果有交点就会有环,所以可以直接用判断单链表是否有环的方法来做。
- 如果两个链表长度相同且存在交点的话,就可以同时一起向后遍历。那么就是先得到两个链表的长度,并让长链表先向后走lenA-lenB步。
因为要让链表保持原有结构,所以只能用第二种方法。且要先判断是否不存在交点的情况。
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
if not headA or not headB:
return None
tempA = headA
tempB = headB
while tempA!=tempB:
tempA = tempA.next
tempB = tempB.next
if not tempA and not tempB:
return None
if not tempA: #A链表后面接上B链表
tempA = headB
if not tempB: #B链表后面接上A链表
tempB = headA
return tempA
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
a, b = headA, headB
l, m = 0, 0
while a:
l += 1
a = a.next
while b:
m += 1
b = b.next
if a != b:
return Null
a, b = headA, headB
if l > m:
diff = l - m
while diff > 0:
a = a.next
diff -= 1
if l < m:
diff = m - l
while diff > 0:
b = b.next
diff -= 1
while a != b:
a = a.next
b = b.next
return a
反转链表
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
解法
- 迭代:循坏迭代算法需要三个临时变量:pre、head、next,只需先保存下cur.next,再让其指向第一个节点即可。临界条件是链表为None或者链表就只有一个节点。
- 递归:思想与迭代相似,关键是让原来指向None的节点,改为指向前一个节点,也就是head.next.next = head,并且截断前一个节点,防止出现环。
迭代
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return head
pre = None
while head:
ne = head.next # 缓存当前节点的向后指针,待下次迭代用
head.next = pre # 这一步是反转的关键,相当于把当前的向前指针作为当前节点的向后指针
pre = head # 作为下次迭代时的(当前节点的)向前指针
head = ne # 作为下次迭代时的(当前)节点
return pre # 返回头指针,头指针就是迭代到最后一次时的head变量(赋值给了pre)
迭代二:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
cur = head
pre = head
while cur and cur.next:
tmp = cur.next
cur.next = cur.next.next
tmp.next = pre
pre = tmp
return tmp
递归:
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
if not head:
return None
if not head.next:
return head
headNode = self.reverseList(head.next)
head.next.next = head
head.next = None
return headNode
两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.
解法
首先,我们交换列表中的前两个节点,也就是 head 和 head.next;
然后我们以 调用函数自身,以交换头两个节点之后列表的其余部分。
最后,我们子列表的返回头与之前的节点相连,以形成新的链表。
注意:要判断节点是否存在以及head.next是否存在
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def swapPairs(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return head
new_h = head.next
cur = new_h.next
new_h.next = head
head.next = self.swapPairs(cur)
return new_h
回文链表
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
解法
开始想到的方法是直接用翻转链表的方法把链表翻转后判断是否相同即可,其中要用到deepcopy,不然会改变原始链表的指针,但是发现空间占用太大(因为深拷贝?)最后一个用例没有通过。
优化方法是走到链表的中间部分,然后将后半部分翻转,判断是否相同即可。
第一种错误方法:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
if not head or not head.next:
return True
pre = None
cur = copy.deepcopy(head)
while cur:
ne = cur.next
cur.next = pre
pre = cur
cur = ne
cur = head
while cur:
if cur.val != pre.val:
return False
cur = cur.next
pre = pre.next
return True
改进:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
if not head or not head.next:
return True
fast = slow = head
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
cur = slow.next
pre = None
while cur:
ne = cur.next
cur.next = pre
pre = cur
cur = ne
cur = head
while pre:
if cur.val != pre.val:
return False
cur = cur.next
pre = pre.next
return True
删除链表中的节点
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
现有一个链表 – head = [4,5,1,9],它可以表示为:
示例 1:
输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:
输入: head = [4,5,1,9], node = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
说明:
链表至少包含两个节点。
链表中所有节点的值都是唯一的。
给定的节点为非末尾节点并且一定是链表中的一个有效节点。
不要从你的函数中返回任何结果。
解法
仅给了需要被删除的节点,又不能得到node的前节点,所以只能通过将node.next的值赋值给node的方式删除。
因为已知不是最后一个,所以不需要判断None
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def deleteNode(self, node):
"""
:type node: ListNode
:rtype: void Do not return anything, modify node in-place instead.
"""
node.val = node.next.val
node.next = node.next.next
奇偶链表
给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
请尝试使用原地算法完成。你的算法的空间复杂度应为 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
说明:
应当保持奇数节点和偶数节点的相对顺序。
链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。
解法
类似于删除单链表中重复的值的题目:设置两个指针,遇到重复的跳过指向下一个节点即可。
空间复杂度是O(1)表示不要新建链表或者数组,时间复杂度O(nodes)表示只循环走一遍链表,原地算法表示直接对head进行修改。
只需设置两个指针,odd和even,odd.next=even.next,even.next=odd.next,并提前设置一个t指针,用于在odd的尾指向even的头。
注意:while的判断条件应该是对even和even.next进行判断,而不是odd,因为odd的已经在前面判断过了。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def oddEvenList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return head
odd = head
even = head.next
t = even
while even and even.next:
odd.next = even.next
odd = odd.next
even.next = odd.next
even = even.next
odd.next = t
return head
复制带随机指针的链表
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的 深拷贝。
我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
提示:
-10000 <= Node.val <= 10000
Node.random 为空(null)或指向链表中的节点。
节点数目不超过 1000 。
解法
类似于图有邻居的题型,用字典存储下新老节点的对应关系。对于新建节点的时候,只能新建(val, None, None),next和random都后面用字典找到对应节点。
"""
# Definition for a Node.
class Node:
def __init__(self, x, next=None, random=None):
self.val = int(x)
self.next = next
self.random = random
"""
class Solution(object):
def copyRandomList(self, head):
"""
:type head: Node
:rtype: Node
"""
if head == None:
return None
dic = {}
cur = head
while cur:
dic[cur] = Node(cur.val, None, None)
cur = cur.next
for key, val in dic.items():
if key.next:
val.next = dic[key.next]
if key.random:
val.random = dic[key.random]
return dic[head]
设计链表
设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。
在链表类中实现这些功能:
get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
示例:
MyLinkedList linkedList = new MyLinkedList();
linkedList.addAtHead(1);
linkedList.addAtTail(3);
linkedList.addAtIndex(1,2); //链表变为1-> 2-> 3
linkedList.get(1); //返回2
linkedList.deleteAtIndex(1); //现在链表是1-> 3
linkedList.get(1); //返回3
提示:
所有val值都在 [1, 1000] 之内。
操作次数将在 [1, 1000] 之内。
请不要使用内置的 LinkedList 库。
解法
题意:定义链表的各种操作
注意:可以保存一个size值,头结点设置为伪节点,这样就不用判断头结点是否存在了。
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class MyLinkedList:
def __init__(self):
self.size = 0
self.head = ListNode(0) # sentinel node as pseudo-head
def get(self, index: int) -> int:
"""
Get the value of the index-th node in the linked list. If the index is invalid, return -1.
"""
# if index is invalid
if index < 0 or index >= self.size:
return -1
curr = self.head
# index steps needed
# to move from sentinel node to wanted index
for _ in range(index + 1):
curr = curr.next
return curr.val
def addAtHead(self, val: int) -> None:
"""
Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.
"""
self.addAtIndex(0, val)
def addAtTail(self, val: int) -> None:
"""
Append a node of value val to the last element of the linked list.
"""
self.addAtIndex(self.size, val)
def addAtIndex(self, index: int, val: int) -> None:
"""
Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted.
"""
# If index is greater than the length,
# the node will not be inserted.
if index > self.size:
return
# [so weird] If index is negative,
# the node will be inserted at the head of the list.
if index < 0:
index = 0
self.size += 1
# find predecessor of the node to be added
pred = self.head
for _ in range(index):
pred = pred.next
# node to be added
to_add = ListNode(val)
# insertion itself
to_add.next = pred.next
pred.next = to_add
def deleteAtIndex(self, index: int) -> None:
"""
Delete the index-th node in the linked list, if the index is valid.
"""
# if the index is invalid, do nothing
if index < 0 or index >= self.size:
return
self.size -= 1
# find predecessor of the node to be deleted
pred = self.head
for _ in range(index):
pred = pred.next
# delete pred.next
pred.next = pred.next.next
环形链表 II
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。
进阶:
你是否可以不用额外空间解决此题?
解法
- 最直接的方法:从前往后,依次断开pre和cur当前的连接,如果从cur开始没有环了,说明环的起始位置是pre。但是这样会超时。
- 设置快慢指针,快指针是慢指针的几倍,就会转几圈与慢指针相遇。相遇点距环入口的距离,等于头结点距环入口的距离。
第一种方法,超时:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return None
fast = slow = head
flag = 0
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
flag = 1
break
if flag == 0:
return None
idx = 0
while True:
tmp = head
for i in range(idx):
tmp = tmp.next
pre = tmp
cur = tmp.next
fast = slow = cur
pre.next = None
flag = 0
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
flag = 1
break
pre.next = cur
if flag == 0:
return pre
idx += 1
第二种方法:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return None
fast = slow = head
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
pre = head
while pre != slow:
pre = pre.next
slow = slow.next
return pre
return None
删除链表的倒数第N个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
解法
- 可以观察到,删除的位置其实就是列表的长度-n-1。所以很容易想到用一个字典存储下每个位置的指针。注意对要移除头结点时的特殊处理即可
- 一次遍历单链表即可。 首先,用两个指针p,q分别指向头结点,然后先将其中一个指针p向后移动N个位置,再将p,q同时往后移动,当指针p移动到末尾时,q指针指向的结点即为我们要删除的结点
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
dic = {}
cur = head
idx = 0
dic[idx] = cur
while cur.next:
cur = cur.next
idx += 1
dic[idx] = cur
rm_idx = idx - n
if rm_idx == -1:
head = head.next
else:
pre = dic[rm_idx]
pre.next = pre.next.next
return head
#coding=utf-8
# Definition for singly-linked list.
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
fast, low = head
while fast and n > 0:
fast = fast.next
n -= 1
if not fast:
return head
while fast.next:
low = low.next
fast = fast.next
low.next = low.next.next
return head
移除链表元素
删除链表中等于给定值 val 的所有节点。
示例:
输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5
解法
题意:删除给定值的所有节点。所以主要是要考虑head的情况
比较简单的方法,新建一个头部伪节点,这样真正的head就可以当做正常节点一起处理了。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def removeElements(self, head, val):
"""
:type head: ListNode
:type val: int
:rtype: ListNode
"""
first = ListNode(0)
first.next = head
cur = first
while cur.next:
if cur.next.val == val:
cur.next = cur.next.next
else:
cur = cur.next
return first.next
合并两个有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
解法
可以用迭代或者递归的归并排序:
迭代法:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def mergeTwoLists(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
if not l1 and not l2:
return None
if not l1 or not l2:
return l1 if l1 else l2
l = ListNode(0)
cur = l
while l1 and l2:
if l1.val < l2.val:
cur.next = l1
l1 = l1.next
else:
cur.next = l2
l2 = l2.next
cur = cur.next
if l1:
cur.next = l1
if l2:
cur.next = l2
return l.next
递归法:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
if not l1 and not l2:
return None
if not l1 or not l2:
return l1 if l1 else l2
head = ListNode(0)
cur = head
if l1.val < l2.val:
cur.next = l1
l1 = l1.next
else:
cur.next = l2
l2 = l2.next
cur = cur.next
cur.next = self.mergeTwoLists(l1, l2)
return head.next
合并K个升序链表
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
解法
- 优先级队列:最小堆(优先队列)维护k个链表的当前头位置的值。考虑优先队列中的元素不超过 k 个,那么插入和删除的时间代价为 O(logk),这里最多有 kn个点,对于每个点都被插入删除各一次,故总的时间代价即渐进时间复杂度为 O(kn×logk)。空间复杂度:这里用了优先队列,优先队列中的元素不超过 k 个,故渐进空间复杂度为 O(k)。
- 链表两两合并,递归「向上回升」的过程,渐进时间复杂度为 O(kn×logk)。递归会使用到O(logk) 空间代价的栈空间。
方法一:
# Definition for singly-linked list.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
if not lists or len(lists) == 0:
return None
import heapq
heap = []
# 首先 for 嵌套 while 就是将所有元素都取出放入堆中
for node in lists:
while node:
heapq.heappush(heap, node.val)
node = node.next
dummy = ListNode(None)
cur = dummy
# 依次将堆中的元素取出(因为是小顶堆,所以每次出来的都是目前堆中值最小的元素),然后重新构建一个列表返回
while heap:
temp_node = ListNode(heappop(heap))
cur.next = temp_node
cur = temp_node
return dummy.next
方法二:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
if not lists:return
n = len(lists)
return self.merge(lists, 0, n-1)
def merge(self,lists, left, right):
if left == right:
return lists[left]
mid = left + (right - left) // 2
l1 = self.merge(lists, left, mid)
l2 = self.merge(lists, mid+1, right)
return self.mergeTwoLists(l1, l2)
def mergeTwoLists(self,l1, l2):
if not l1:return l2
if not l2:return l1
if l1.val < l2.val:
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
else:
l2.next = self.mergeTwoLists(l1, l2.next)
return l2
两数相加
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
解法
类似于归并操作的复杂版
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
l = ListNode(0)
cur = l
flag = 0
while l1 and l2:
tmp = l1.val + l2.val + flag
if tmp < 10:
tmp2 = tmp
flag = 0
else:
tmp2 = tmp - 10
flag = 1
x = ListNode(tmp2)
cur.next = x
l1 = l1.next
l2 = l2.next
cur = cur.next
rest = l1 if l1 else l2
while rest:
tmp = rest.val + flag
if tmp < 10:
tmp2 = tmp
flag = 0
else:
tmp2 = tmp - 10
flag = 1
x = ListNode(tmp2)
cur.next = x
rest = rest.next
cur = cur.next
if flag == 1:
x = ListNode(1)
cur.next = x
return l.next
扁平化多级双向链表
您将获得一个双向链表,除了下一个和前一个指针之外,它还有一个子指针,可能指向单独的双向链表。这些子列表可能有一个或多个自己的子项,依此类推,生成多级数据结构,如下面的示例所示。
扁平化列表,使所有结点出现在单级双链表中。您将获得列表第一级的头部。
示例:
输入:
1---2---3---4---5---6--NULL
|
7---8---9---10--NULL
|
11--12--NULL
输出:
1-2-3-7-8-11-12-9-10-4-5-6-NULL
解法
题意:不断的将子链表插入回去
方法:使用递归,找到没有child的子链表,返回头尾节点,并插入回去
注意:双链表在插入时注意判断cur.next是否存在;递归返回的尾结点要用一个指针保存下来。
"""
# Definition for a Node.
class Node(object):
def __init__(self, val, prev, next, child):
self.val = val
self.prev = prev
self.next = next
self.child = child
"""
class Solution(object):
def flatten(self, head):
"""
:type head: Node
:rtype: Node
"""
h, t = self.dfs(head)
return h
def dfs(self, head):
h = cur = pre = head
while cur:
if cur.child:
c_h, c_t = self.dfs(cur.child)
cur.child = None
c_h.prev = cur
c_t.next = cur.next
if cur.next:
cur.next.prev = c_t
cur.next = c_h
pre = cur
cur = cur.next
return h, pre
旋转链表
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
解法
题意:将链表向右旋转K步的结果
步骤:
- 首先给定的k要对长度求余才是真正要移动的步数;
- 如何旋转:找到length - k - 1的位置pre,让pre.next = None,让尾结点连上头结点即可
- 注意:当k%length == 0 的时候要特殊处理,不然最后的返回会越界。
- 用dic存储下来每个位置的指针,比较方便寻找
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def rotateRight(self, head, k):
"""
:type head: ListNode
:type k: int
:rtype: ListNode
"""
if not head or not head.next or k == 0:
return head
dic = {}
cur = head
idx = 0
while cur:
dic[idx] = cur
cur = cur.next
idx += 1
if k % idx == 0:
return head
point = idx - (k % idx) - 1
pre = dic[point]
pre.next = None
dic[idx - 1].next = head
return dic[point + 1]