所有例题的编程语言为python
leetcode 206
思路1: 迭代求解,将当前结点next信息保存下来,然后将前一个节点的信息存入当前结点的next中。更新当前结点。
# 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 head==None:
return head
pre_node=None
cur_node=head
while(cur_node):
next_node=cur_node.next
cur_node.next=pre_node
pre_node=cur_node
cur_node=next_node
return pre_node
思路2:
递归:假设链表的其余部分都已经被翻转,现在该如何翻转它前面的部分。由最后一个开始往前不断翻转
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if head==None or head.next==None:
return head
p=self.reverseList(head.next) # 记录最后一个结点作为头指针用的。
head.next.next=head
head.next=None
return p
删除链表中等于给定值 val 的所有节点。
思路:遍历链表的每一结点,如果值等于给定值将其删除即可。
注意点:要删除链表节点时,可以使用哑结点技巧,防止删原链表的头结点。最后返回时,返回dummy.next即可。
# 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
"""
dummy=ListNode(0)
dummy.next=head
pre_node=dummy
cur_node=dummy.next
while(cur_node):
next_node=cur_node.next
if cur_node.val==val:
pre_node.next=next_node # 删除结点
else:
pre_node=cur_node
cur_node=next_node
return dummy.next
给定一个单链表,把所有奇数节点和偶数节点(节点 编号的奇偶性)分别排在一起。
思路1:原来的链表分成奇偶两个子链表,然后将偶链表链接到奇链表后面。
没有使用额外的空间,直接从原来的链表中截取。
# 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 head==None:
return head
even_h=ListNode(0)
even_node=even_h
cur_node=head
i=1
while(cur_node):
next_node=cur_node.next
if i %2==0:
cur_node.next=None # 将node.next的值给设置为零,能防止成环
even_node.next=cur_node
even_node=even_node.next
pre_node.next=next_node
else:
pre_node=cur_node
cur_node=next_node
i+=1
cur_node=head.next
pre_node=head
while(cur_node):
print(pre_node.val)
pre_node=cur_node
cur_node=cur_node.next
pre_node.next=even_h.next
return head
判断一个链表是否为回文链表。
o(n)时间复杂度,o(1)空间复杂度
思路1:可以先把链表装进数组中,判断数组中元素是否构成回文。数组的前后遍历比单链表方便。时间复杂度o(n),空间复杂度o(n)
# 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
lst=[]
p=head
while(p):
lst.append(p.val)
p=p.next
return lst==lst[::-1]
思路2:翻转原链表,对照两个链表是否一致,如果回文链表应该是一致的,反之原链表不为回文链表。时间复杂度o(n),空间复杂度o(n)
# 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 head==None or head.next==None:
return True
# 备份原链表
head_be=ListNode(0)
node=head
node_be=head_be
while(node):
node_be.next=ListNode(node.val)
node_be=node_be.next
node=node.next
# 转置原链表
pre_node=None
cur_node=head
while(cur_node):
next_node=cur_node.next
cur_node.next=pre_node
pre_node=cur_node
cur_node=next_node
# 比较两个链表
node_be=head_be.next
node_af=pre_node
while(node_be and node_af):
if node_be.val!=node_af.val:
return False
node_be=node_be.next
node_af=node_af.next
return True
思路三:避免使用 O(n)O(n) 额外空间的方法就是改变输入。
我们可以将链表的后半部分反转(修改链表结构),然后将前半部分和后半部分进行比较。比较完成后我们应该将链表恢复原样。虽然不需要恢复也能通过测试用例,因为使用该函数的人不希望链表结构被更改。
class Solution(object):
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
if not head or not head.next:
return True
# 计算链表长度
p1=head
n=1
while(p1.next):
p1=p1.next
n+=1
p1=head
p2=head
if n==2:
if head.val==head.next.val:
return True
else:
return False
# 找链表中点
for i in range(int(round(n/2.0))-1): # 0
p1=p1.next
half_end=p1 # 前一半链表的最后一个节点
# 翻转后一半链表
p1=p1.next
pre_node=None
for i in range(int(n/2.0)): # 0,1
next_node=p1.next
p1.next=pre_node
pre_node=p1
p1=next_node
half_end.next=pre_node
p1=head
# 比较前一半和翻转后的后一半。
for i in range(int(round(n/2.0))): # 0,1
p1=p1.next
for i in range(int(n/2)):# 0,1
if p1.val!=p2.val:
return False
p1=p1.next
p2=p2.next
return True
1.使用链表时不易调试,自己多尝试几个测试用例总是很有用的,通过输出链表节点的值来观测代码运行情况。
2.多指针时,为指针设定合适的名称,防止自己被搞混
3.单链表操作时,储存前一个节点的信息往往是有效的。