1、反转链表(206)
题目描述:
【简单题】
思路分析:
题解一:迭代
1、通过上图分析,反转链表相当于改变每一节点的next指针为前一节点。由于在转变过程中,涉及到前一节点,当前节点,遍历完当前节点转场的下一节点,则可以设置三个指针(pre前指针,cur当前指针,nxt下一指针),从而实现反转。
2、初始pre为空指针,代表前一节点;cur为头节点head,代表当前节点;
3、当前节点cur不为空时,进行循环:
- 下一节点nxt=cur.next
- 当前节点的指针为前一节点pre,实现局部反转。
- 移动前一节点pre为当前节点cur
- 移动当前节点cur为下一节点
4、返回链表即头节点pre
【python3实现代码】
# 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:
pre=None
cur=head
while cur:
nxt=cur.next
cur.next=pre
pre=cur
cur=nxt
return pre
- 时间复杂度: O ( n ) O(n) O(n),假设 n n n 是列表的长度,
- 空间复杂度: O ( 1 ) O(1) O(1)。
题解二:递归
1、递归就是调用自己的函数,对于此题来说:相对于现头结点来说,它只需要知道它之后的所有节点反转之后的结果就可以了,也就是说递推公式reverseList的含义是:把拿到的链表进行反转,然后返回新的头结点。
2、再反转头结点:head.next.next=head,head.next=None
代码实现:
# 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
newhead=self.reverseList(head.next)
head.next.next=head
head.next=None
return newhead
-
时间复杂度:O(n),其中 n 是链表的长度。需要对链表的每个节点进行反转操作。
-
空间复杂度:O(n),其中 n 是链表的长度。空间复杂度主要取决于递归调用的栈空间,最多为 n 层。
2、反转链表II(92)
题目描述:
【中等题】
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
思路分析:
题解一:迭代
此题与上一题的区别是仅区间内反转,所以相对于上题需做以下两步:
- 找到m位置的节点和m位置的前置节点pre
- 另外,我们要引入两个额外指针,分别称为 tail 和 con。tail 指针指向从链表头起的第m个结点,此结点是反转后子链表的尾部,故称为 tail。con 指针指向第 m 个结点的前一个结点,此结点是新链表的头部。下图可以帮助你更好的理解这两个指针。利用两指针调整链表。
- 当区间内的链表进行反转后,我们使用 con 指针来连接 prev 指针,这是因为 prev 指针当前指向的结点(第 n 个结点)会代替第 m 个结点的位置。 类似地,我们利用 tail 指针来连接 prev 指针之后的结点(第 n+1 个结点)。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
if not head:
return None
pre,cur,i=None,head,1
while i<m:
pre=cur
cur=cur.next
i+=1
tail,con=cur,pre
while i<=n:
nxt=cur.next
cur.next=pre
pre=cur
cur=nxt
i+=1
if con:
con.next,tail.next=pre,cur
return head
else:
tail.next=cur
head=pre
return head
-
时间复杂度: O ( n ) O(n) O(n),假设 n n n 是列表的长度,
-
空间复杂度: O ( 1 ) O(1) O(1)。
题解二:递归
思路:
代码实现:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
if left==1:
return self.reverseTopN(head,right)
between = self.reverseBetween(head.next, left-1,right-1)
head.next = between
return head
topNSuccessor=None
#定义反转前n个节点链表
def reverseTopN(self, head: ListNode, right: int) -> ListNode:
global topNSuccessor #全局变量
if right==1:
topNSuccessor=head.next
return head
newhead=self.reverseTopN(head.next,right-1)
head.next.next=head
head.next=topNSuccessor
return newhead
3、删除排序链表中的重复元素(83)
题目描述:
【简单题】
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
思路分析:
1.由于链表已经排序,删除重复元素,只需从前到后判断当前元素是否与后面元素重复,若重复,删除其中一个即可
2.由于链表结点的特征性,因此我们可以通过将当前结点的值与它之后的结点进行比较来确定它是否为重复结点。可设置一个当前节点指针cur
- 如果它是重复的,我们更改当前结点cur的 next 指针为cur.next.next,以便它跳过下一个结点并直接指向下一个结点之后的结点。
- 如果不是重复的,则将cur指针移动到下一位置即cur.next。
关键点:指针的是否改变
【python3 实现】
# 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 None
cur=head
while cur.next:
if cur.val==cur.next.val:
cur.next=cur.next.next
else:
cur=cur.next
return head
4、分隔链表(86)
题目描述:
【中等题】
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
思路分析:
1、大小链表,最后拼接
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def partition(self, head: ListNode, x: int) -> ListNode:
dummy1 = ListNode(-1)
dummy2 = ListNode(-1)
p1 = dummy1
p2 = dummy2
while head:
if head.val < x:
p1.next = head
p1 = p1.next
else:
p2.next = head
p2 = p2.next
head = head.next
p1.next = dummy2.next
p2.next = None
return dummy1.next