赞
踩
简单题,双指针就可以,还有一个传值还是传引用的问题可以看这篇:python函数传参是传值还是传引用?
# Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: dummy = ListNode() p = dummy while list1 != None and list2 != None: if list1.val < list2.val: p.next = list1 list1 = list1.next p = p.next elif list2.val <= list1.val: p.next = list2 list2 = list2.next p = p.next if list1 != None: p.next = list1 if list2 != None: p.next = list2 return dummy.next
与上面那道题一样的思路,只不过上面那道题只需要比较两个指针的值,这道题有k个,要是挨个比较要o(k)的复杂度。但是我们可以用priority queue这个数据结构把时间复杂度降到o(logk)
python 里面priority queue怎么用,看这篇文章: 用Python实现优先级队列
# Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def mergeKLists(self, lists: List[ListNode]) -> ListNode: def __lt__(self, other): return self.val < other.val ListNode.__lt__ = __lt__ dummy = ListNode() p = dummy heap = [] for ln in lists: if ln: heapq.heappush(heap, ln) while heap: smallest = heapq.heappop(heap) p.next = smallest p = p.next if smallest.next: heapq.heappush(heap, smallest.next) return dummy.next
注意的点有:
以上这些题都可以用快慢指针来做
如果用两个指针 p1 和 p2 分别在两条链表上前进,并不能同时走到公共节点,也就无法得到相交节点 c1。
解决这个问题的关键是,通过某些方式,让 p1 和 p2 能够同时到达相交节点 c1。
所以,我们可以让 p1 遍历完链表 A 之后开始遍历链表 B,让 p2 遍历完链表 B 之后开始遍历链表 A,这样相当于「逻辑上」两条链表接在了一起。
如果这样进行拼接,就可以让 p1 和 p2 同时进入公共部分,也就是同时到达相交节点 c1
需要注意的是,不相交的情况也可以看作相交于None这个节点,也就是下图c1是None的情况
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
pa = headA
pb = headB
while pa != pb:
if pa:
pa = pa.next
else:
pa = headB
if pb:
pb = pb.next
else:
pb = headA
return pa
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
if head is None or head.next is None:
return head
last = self.reverseList(head.next)
head.next.next = head
head.next = None
return last
这里注意basecase 当链表为空或者只有一个节点, 反转就是自身
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
prev = None
cur = head
while cur:
next = cur.next
cur.next = prev
prev = cur
cur = next
return prev
prev->cur->next
注意为什么要先取得next, 其实next相当于一个temp变量, 暂时把cur的下一个节点存起来,因为接下来cur要与prev相连用于颠倒指针指向, 如果没有存next, cur将无法移动到下一个节点.
cur与prev相连之后可以把cur和prev同时向后移动一位
def reverseN(head, right):
if right == 1:
successor = head.next
return head, successor
last, successor = reverseN(head.next, right-1)
head.next.next = head
head.next = successor
return last, successor
1、base case 变为 n == 1,反转一个元素,就是它本身,同时要记录后驱节点。
2、刚才我们直接把 head.next 设置为 null,因为整个链表反转后原来的 head 变成了整个链表的最后一个节点。但现在 head 节点在递归反转之后不一定是最后一个节点了,所以要记录后驱 successor(第 n + 1 个节点),反转之后将 head 连接上。
第二步:
class Solution: def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode: def reverseN(head, right): if right == 1: successor = head.next return head, successor last, successor = reverseN(head.next, right-1) head.next.next = head head.next = successor return last, successor if left == 1: return reverseN(head, right)[0] head.next = self.reverseBetween(head.next, left-1, right-1) return head
class Solution: def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode: dummy = ListNode(-1) dummy.next = head p = dummy pos = 1 while pos < left: p = p.next pos += 1 # 现在p在需要被反转的头节点的前一位 pre pre = p while pos <= right + 1: p = p.next pos += 1 # 现在p在需要被反转的链表的后一位 suc suc = p prev = suc cur = pre.next while cur is not suc: next = cur.next cur.next = prev prev = cur cur = next pre.next = prev return dummy.next
方法二: 一次遍历「穿针引线」反转链表(头插法)
方法一的缺点是:如果 left 和 right 的区域很大,恰好是链表的头节点和尾节点时,找到 left 和 right 需要遍历一次,反转它们之间的链表还需要遍历一次,虽然总的时间复杂度为 O(N),但遍历了链表 2 次,可不可以只遍历一次呢?答案是可以的。我们依然画图进行说明。
class Solution: def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode: dummy = ListNode(-1) dummy.next = head p = dummy for _ in range(left - 1): p = p.next prehead = p prev = prehead.next cur = prev.next for _ in range(right - left): next = cur.next cur.next = prehead.next 这里要注意 prehead.next = cur prev.next = next cur = next return dummy.next
# Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def reverseKGroup(self, head: ListNode, k: int) -> ListNode: def reverseList(head: ListNode, tail: ListNode): prev = tail cur = head while cur != tail: next = cur.next cur.next = prev prev = cur cur = next newhead = prev newtail = head return newhead, newtail p = head dummy = ListNode(-1) dummy.next = head lasttail = dummy while head: for _ in range(k): if not head: return dummy.next head = head.next nexthead = head curhead = lasttail.next newhead, newtail = reverseList(curhead, nexthead) lasttail.next = newhead lasttail = newtail return dummy.next
这道题的关键在于,单链表无法倒着遍历,无法使用双指针技巧。
void traverse(TreeNode root) {
// 前序遍历代码
traverse(root.left);
// 中序遍历代码
traverse(root.right);
// 后序遍历代码
}
链表的可以写成
void traverse(ListNode head) {
// 前序遍历代码
traverse(head.next);
// 后序遍历代码
}
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
left = head
def traverse(right):
if not right:
return True
nonlocal left
res = traverse(right.next)
res = res and right.val == left.val
left = left.next
return res
return traverse(head)
方法二:
那么最简单的办法就是,快慢指针找到中点然后反转后面的链表, 然后比较.
有几点需要注意
class Solution: def isPalindrome(self, head: ListNode) -> bool: def reverseList(head): prev = None cur = head while cur: next = cur.next cur.next = prev prev = cur cur = next return prev slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next if fast: #总共有奇数 1->2->3->2->1 slow = slow.next right = reverseList(slow) left = head while right: if right.val != left.val: return False right = right.next left = left.next return True
class Solution: def isPalindrome(self, head: ListNode) -> bool: def reverseList(head): prev = None cur = head while cur: next = cur.next cur.next = prev prev = cur cur = next return prev slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next if fast: #总共有奇数 1->2->3->2->1 slow = slow.next righthead = reverseList(slow)# 注意区别 right = righthead left = head while right and right.next: # 注意区别 if right.val != left.val: return False right = right.next left = left.next if right and left.val != right.val:# 注意区别 return False# 注意区别 left.next = reverseList(righthead)# 注意区别 return True
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。