将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
解法
很简单的链表拼接题,但是要注意两个地方
1、返回值要返回head.next
2、无需判断循环后哪个不为空,or返回第一个为真的值
# 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:
head = cur = ListNode(0)
while l1 and l2:
if l1.val > l2.val:
cur.next = l2
l2 = l2.next
else:
cur.next = l1
l1 = l1.next
cur = cur.next
cur.next = l1 or l2
return head.next
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:
输入: 1->1->2
输出: 1->2
示例 2:
输入: 1->1->2->3->3
输出: 1->2->3
解法1
从链表中删除元素,一般需要两个指针来完成,分别记录要删除的链表元素和上一个元素。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
if not head:
return head
p = head
q = head.next
while q:
if p.val == q.val:
p.next = q.next
q = q.next
else:
p = p.next
q = q.next
return head
解法2
两个指针比较容易理解,但是这里其实用一个指针就可以完成
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
cur = head
while cur:
while cur.next and cur.val == cur.next.val:
cur.next = cur.next.next
cur = cur.next
return head
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 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
解释:链表中没有环。
解法
判断链表中是否是有环,采用追赶法的思路,设置一个walker,每次走一步,设置一个runner,每次跑两步,当runner追上walkder时,说明链表中有环存在。
# 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
"""
fast = slow = head
while fast and slow and fast.next:
slow = slow.next
fast = fast.next.next
if slow is fast:
return True
return False
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 1:
输入: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 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。
注意:
如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
解法
判断链表是否有交集,可以设置两个指针,一个指针从第一个链表开始遍历,遍历完第一个链表再遍历第二个链表,另一个指针从第二个链表开始遍历,遍历完第二个链表再遍历第一个链表,不管两个链表在交集前的长度如何,如果有交集的话,两个指针肯定会同时遍历到最后的交集部分。
# 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
"""
if not headA or not headB:
return None
pa = headA
pb = headB
while pa is not pb:
pa = headB if pa == None else pa.next
pb = headA if pb == None else pb.next
return pa
一图胜千言,看图你就明白了
空间复杂度O(1) 时间复杂度为O(n)
这里使用图解的方式,解释比较巧妙的一种实现。
根据题目意思 如果两个链表相交,那么相交点之后的长度是相同的
我们需要做的事情是,让两个链表从同距离末尾同等距离的位置开始遍历。这个位置只能是较短链表的头结点位置。 为此,我们必须消除两个链表的长度差
指针pA指向A链表,指针pB指向B链表,依次往后遍历
如果pA到了末尾,则pA = headB 继续遍历
如果pB到了末尾,则pB = headA 继续遍历
比较长的链表指针指向较短链表head时,长度差就消除了
如此,只需要将最短链表遍历两次即可找到位置
听着可能有点绕,看图最直观,链表的题目最适合看图了
参考:https://leetcode-cn.com/problems/two-sum/solution/tu-jie-xiang-jiao-lian-biao-by-user7208t/
删除链表中等于给定值 val 的所有节点。
示例:
输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5
解法
"有了第83题的思路,我们这里可以用一个指针来进行链表的遍历,但是这里需要注意的是,头节点也需要进行判断,如果头节点的值等于val的话,我们不能返回头节点,所以这里很巧妙的重新生成了一个无关的头节点。
class Solution(object):
def removeElements(self, head, val):
"""
:type head: ListNode
:type val: int
:rtype: ListNode
"""
dummy = ListNode(-1)
dummy.next = head
cur = dummy
while cur:
while cur.next and cur.next.val == val:
cur.next = cur.next.next
cur = cur.next
return dummy.next
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
解法
链表转置,这里实在想不到一个指针的解法了,只能用两个指针,再加上head的帮忙,p指针记录的是每次的队头元素,q指针指向下一个要插入队头的元素。
if not head:
return None
p = head
q = head.next
while q:
head.next = q.next
q.next = p
p = q
q = head.next
return p
# 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
"""
cur, pre = head, None
while cur:
cur.next, pre, cur = pre, cur, cur.next
return pre
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
解法
判断一个链表是否是回文的,很自然的想法就是两个指针,一个指针从前往后走,一个指针从后往前走,判断元素值是否相同,这里要分几个步骤来进行求解:
1、找到链表长度的一半,用追赶法,一个指针一次走两步,一个指针一次走一步
2、将后一半数组转置
3、判断链表是否是回文链表
# 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
"""
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
node = None
while slow:
nxt = slow.next
slow.next = node
node = slow
slow = nxt
while node and head:
if node.val != head.val:
return False
node = node.next
head = head.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.
解法
这道题关键是理解题意,不给你整个链表,只给你一个节点,如何把这个节点删除,其实我们没必要真的把这个节点删除,而是把这个节点对应的val值删除即可,所以我们可以偷天换日,把下一个节点的值赋给这个节点,再把下一个节点删除。
在这里插入代码片# 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