前言
24. 两两交换链表中的节点
思路
奇数节点最后一个不交换,偶数节点两两交换正好
交换相邻两个元素了,此时一定要画图,不画图,操作多个指针很容易乱,而且要操作的先后顺序;
老师的思路需要两个tmp变量
注意点
- 注意交换顺序
- ✨注意终止条件:next和next.next不为空【需要记住的】;这一句判断就可以包括奇数和偶数的情况
注意 while语句判别条件的两个位置不能交换,否则self.next.next会有可能是空的
- 注意curr一定要指向要交换的节点的前一个节点
- 注意curr每次往后移动两位
"""
carl 的代码,挺简单的,一目了然
"""
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
dummy_head = ListNode(next=head)
current = dummy_head
# 必须有cur的下一个和下下个才能交换,否则说明已经交换结束了
while current.next and current.next.next:
temp = current.next # 防止节点修改
temp1 = current.next.next.next
current.next = current.next.next
current.next.next = temp
temp.next = temp1
current = current.next.next
return dummy_head.next
我自己的方法
图是用这个画的
按照这个顺序写的,也可以,只需要使用一个中间变量就行
😶我犯的错误
- 忘了处理完之后移动curr到next.next的位置
- return的应该是虚拟头节点的下一个
class Solution(object):
def swapPairs(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
self.dammy_Node = ListNode(0,head)
curr = self.dammy_Node
while curr.next!=None and curr.next.next!=None:
#注意:1两个条件不能交换顺序,必须先判断curr.next是否为空;2. 如果curr.next为空就是偶数个的情况,如果curr.next.next为空就是奇数个情况,同样也不处理
tmp = curr.next.next.next
curr.next.next.next = curr.next
curr.next = curr.next.next
curr.next.next.next = tmp
curr = curr.next.next #记得更新到下下个节点的位置
return self.dammy_Node.next #指向虚拟节点的下一个
19.删除链表的倒数第N个节点
思路:快慢指针
这题的思想依旧十分巧妙
使用快慢指针的方法;还是需要使用虚拟头节点的方法
✨重难点:如何一次遍历就可以找到倒数第n个节点呢?让快指针比慢指针先走n个节点,然后快、慢指针同时前进,当快指针指向None的时候,慢指针指向倒数第n个节点
注意细节:由前面的经验可以知道,指针应该要指向被操作节点的同一个,也就是慢指针应该指向倒数第n个节点的前一个指针;
解决思路一:老师版本,让fast比slow的提前走n+1个,当fast指向null的时候,slow指向前一个
解决思路二:我自己想的,fast比slow提前走n个,当fast的next指向空的时候,slow指向前一个
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
# 创建一个虚拟节点,并将其下一个指针设置为链表的头部
dummy_head = ListNode(0, head)
# 创建两个指针,慢指针和快指针,并将它们初始化为虚拟节点
slow = fast = dummy_head
# 快指针比慢指针快 n+1 步
for i in range(n+1):
fast = fast.next
# 移动两个指针,直到快速指针到达链表的末尾
while fast:
slow = slow.next
fast = fast.next
# 通过更新第 (n-1) 个节点的 next 指针删除第 n 个节点
slow.next = slow.next.next
return dummy_head.next
我的思路的代码,非常简单
"""
我的思路的代码,非常简单
"""
class Solution(object):
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
self.dammy_head = ListNode(0,head)
fast,slow = self.dammy_head,self.dammy_head
#让fast先走n个
while n:
fast = fast.next
n -= 1
#fast&slow同时走
while fast.next!=None:
fast = fast.next
slow = slow.next
# 删除节点操作
slow.next = slow.next.next
return self.dammy_head.next
面试题 02.07. 链表相交
思路
这个题目拿到手还是一点思路都没有
解法:我们求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 末尾对齐的位置,如
此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到交点。否则为空
时间复杂度:O(n + m)
空间复杂度:O(1)
下面是老师写的版本:
可以学习的地方在于
- 将curB设置为最长链表的头
- 后面同时前进的时候遍历while的条件语句为curA不为none,然后while里面判断是否为同一个节点,比我的代码简洁
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
lenA, lenB = 0, 0
cur = headA
while cur: # 求链表A的长度
cur = cur.next
lenA += 1
cur = headB
while cur: # 求链表B的长度
cur = cur.next
lenB += 1
curA, curB = headA, headB
if lenA > lenB: # 让curB为最长链表的头,lenB为其长度
curA, curB = curB, curA
lenA, lenB = lenB, lenA
for _ in range(lenB - lenA): # 让curA和curB在同一起点上(末尾位置对齐)
curB = curB.next
while curA: # 遍历curA 和 curB,遇到相同则直接返回
if curA == curB:
return curA
else:
curA = curA.next
curB = curB.next
return None
下面是自己写的python版本,知道思路之后就很简单,没什么要注意的
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
#calculate length of A and B
count_A, count_B = 0,0
curr = headA
pointa,pointb = headA,headB
while curr!=None:
count_A += 1
curr = curr.next
curr = headB
while curr!=None:
count_B += 1
curr = curr.next
print("a size is"+str(count_A)+"b size is "+str(count_B))
if count_A > count_B:
gap = count_A - count_B
#移动curr的指针到和B起始的位置
while gap:
pointa = pointa.next
gap -= 1
else:
gap = count_B - count_A
while gap:
pointb = pointb.next
gap -= 1
while pointa !=pointb and pointa !=None and pointb !=None:
pointa = pointa.next
pointb = pointb.next
# print("pointa val is "+str(pointa.val))
if pointa == pointb:
return pointa
else:
return None
142.环形链表II
思路
这道题目需要数据推导,很不容易
首先使用快慢指针,快指针跑两个格子,慢指针跑一个,如果慢指针和快指针能相遇,那就是有环的,否则没有。
接着推导公式:确认有环之后找到环的入口:x==z【重要结论】
这个公式说明什么呢?
- 补充问题:为什么慢指针一定会在第一圈被快指针追上:fast是走两步,slow是走一步,其实相对于slow来说,fast是一个节点一个节点的靠近slow的,所以fast一定可以和slow重合。下面这个图将转的圈圈展开,可以看到slow在里面转一圈的时候,fast一定给是可以追上去的
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
#首先寻找是否有环
fast,slow = head,head
while fast != None and fast.next:
fast = fast.next.next
slow = slow.next
if fast == slow:#说明有环,index1和index2开始找入口
index1 = head
index2 = slow
while index1 != index2:
index1 = index1.next
index2 = index2.next
return index1
return None