82 删除排序链表中的重复元素 II
两个思路,一个是另外建立一个列表,每次赋值。或者在原链表上进行修改。第一个思路更加清晰,第二个思路更省空间。
对于找到不重复的链表也有两个思路,一个是使用标志位,一个是采用存储重复临时元素。
方法一:构建新链表+移动指针
class Solution(object):
def deleteDuplicates(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return head
node = ListNode(0)
ans = node
flag = 0
while head and head.next:
# 首次遇到重复
if head.val == head.next.val:
flag = 1
# 当前重复结束,但是不知道下一个是否重
elif flag == 1 and head.val != head.next.val:
flag = 0
# 当前不重复,且下一个和目前的不重复
elif flag == 0 and head.val != head.next.val:
node.next = ListNode(head.val)
node = node.next
head = head.next
# !!!注意,可能需要补上最后一个,当前不重复,且后一个是None
if flag == 0:
node.next = ListNode(head.val)
return ans.next
如果才有原地修改也可以:
class Solution(object):
def deleteDuplicates(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return head
ans = ListNode(0)
curr = head
node = ans
while curr and curr.next:
if curr.val == curr.next.val:
temp = curr.val
while curr.next and curr.next.val == temp:
curr = curr.next
# !! 重要,可以防止最后没有结尾
node.next = curr.next
else:
node.next = curr
node = node.next
curr = curr.next
return ans.next
一定要注意每次操作完都要给node.next
一个交代,否则出大问题
86 分割链表
class Solution(object):
def partition(self, head, x):
"""
:type head: ListNode
:type x: int
:rtype: ListNode
"""
if not head or not head.next:
return head
small = small_head = ListNode(0)
large = large_head = ListNode(0)
while head:
if head.val<x:
small.next = head
small = small.next
else:
large.next = head
large = large.next
head = head.next
small.next = large_head.next
large.next = None
return small_head.next
复杂度分析
时间复杂度:
O
(
N
)
O(N)
O(N),其中N是原链表的长度,我们对该链表进行了遍历。
空间复杂度:
O
(
1
)
O(1)
O(1),我们没有申请任何新空间。值得注意的是,我们只移动了原有的结点,因此没有使用任何额外空间。
92 反转链表II
借助这道题,我们来总结一下反转链表那些事。
首先贴上迭代的方法:
class Solution(object):
def reverseBetween(self, head, m, n):
"""
:type head: ListNode
:type m: int
:type n: int
:rtype: ListNode
"""
dummy = ListNode(-1)
dummy.next = head
pre = dummy
# 找到翻转链表部分的前一个节点, 1->2->3->4->5->NULL, m = 2, n = 4 指的是 节点值为1
for _ in range(m-1):
pre = pre.next
# 用双指针,进行链表翻转
node = None
cur = pre.next
for _ in range(n-m+1): # 这个循环的末尾太关键了
cur.next, node, cur = node, cur, cur.next
# 将翻转部分 和 原链表拼接 此时,cur是反转之后的第一个,也就是5
pre.next.next = cur ## pre.next 是2 是反转的开头,也是反转结束的末尾
pre.next = node
return dummy.next
203 删除链表元素
class Solution(object):
def removeElements(self, head, val):
"""
:type head: ListNode
:type val: int
:rtype: ListNode
"""
pre = ListNode(0)
ans = pre
pre.next = head
# 注意逻辑!!如果next需要被删除,删除以后本次不前进,否则会导致跳了一个判断。
while pre.next:
if pre.next.val == val:
pre.next = pre.next.next
else:
pre = pre.next
return ans.nex
- 需要注意,如果next需要被删除,删除以后本次不前进,否则会导致跳了一个判断。
- 用人为加入头节点的方法可以避免一些问题。
206 反转链表
首先是迭代的方法,推荐作为一个模块记住:
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
prev = None
# 遍历链表
while head:
head.next, prev, head = prev, head, head.next
return prev
可以直接背下来。
需要特别注意完成循环以后,prev
是反转以后链表的头,head
实际指向是超出范围的第一个(None)。
递归
class Solution(object):
# 输入一个节点 head,将「以 head 为起点」的链表反转,并返回反转之后的头结点。
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
# 递归终止条件是当前为空,或者下一个节点为空
if not head or not head.next:
return head
# 这里的cur就是最后一个节点
cur = self.reverseList(head.next)
# 如果链表是 1->2->3->4->5,那么此时的cur就是5
# 而head是4,head的下一个是5,下下一个是空
# 所以head.next.next 就是5->4
head.next.next = head
# 防止链表循环,需要将head.next设置为空
head.next = None
# 每层递归函数都返回cur,也就是最后一个节点
return cur