第二遍写思考:昨天看了一点所以也还记得思路。用递归的方法,每次处理两个节点的交换,把第三个节点作为头结点传到下一层递归。因为涉及增删改,所以加一个虚拟头结点会更方便。
思路错误:因为有迭代,不应该设虚拟投节点,不然每次迭代都新建一个头结点,没必要,不如往后再考虑一个节点。
思考:发现是两个算法的思路混在一起了。
算法思路:有时候可以把while当if用,毕竟while也是要判断条件的嘛。
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy_head = ListNode(next = head)
cur = dummy_head
while cur.next and cur.next.next:
temp = cur.next
next_one = cur.next.next.next
cur.next = cur.next.next
cur.next.next = temp
temp.next = next_one
#这里的temp和cur.next.next是一样的,这里也可以写cur = cur.next.next
cur = temp
#每次交换对的第二个就是下一次交换对的虚拟头结点
return dummy_head.next
第三遍写居然通过啦~
接下来写递归。递归的用时和内存都更好呢!
语法思路:发现自己很喜欢用if+某个变量做条件,但是其实要把“变量 is None”也放到视野内考虑,其实更常用。
算法思路:给递归思路画了个图,其实递归对我更好理解:
这个过程等于移动了cur, pre, next_one指针后,只改了两个.next(cur.next和pre.next)。
↑了解了这个思路之后就没什么问题了。
很快啊,我以为是删除正数第N个,啪得就写出来了,写完发现是倒数第N个。
算法思路:链表,用快慢双指针啊!
for i in range(n+1):
fast = fast.next
while fast:
slow = slow.next
fast = fast.next
↑快慢指针的写法,感觉以后会常用。
第二遍写:
注意要用slow.next = slow.next.next,要用.next来操作它的指针,这样才有效。
语法:python注意缩进。
我还以为是有方法获取链表长度呢,原来答案里的getLength方法和moveForward方法都是自己定义的。
dmsxl的答案给了四个版本,其实只给一两个最优解就可以了 - -
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
# 如果其中一个链表为空,则显然不可能有相交节点,因此直接返回 None。
if headA is None or headB is None:
return None
# 初始化两个指针
pointerA = headA
pointerB = headB
# 遍历两个链表直到指针相交
while pointerA != pointerB:
# 将指针向前移动一个节点
pointerA = pointerA.next if pointerA else headB
pointerB = pointerB.next if pointerB else headA
# 如果相交,指针将位于交点节点,如果没有交点,值为None
return pointerA
其实和后面142非常像,都是找链表中两个指针相遇的地方。
问雀头:“为什么两个指针相交时一定是交点?万一后面我们以为完全相交的部分其实有数字不一样呢?”
在这个问题中,相交的定义不是基于节点的值,而是基于节点的内存地址。也就是说,我们判断两个链表是否相交,不是看它们的值是否相等,而是看两个链表是否共享同一个节点对象(即内存地址相同)。这就是题目所强调的“相交是基于引用,而不是值”的原因。
第二个问题:当两个指针都走了m+n步后,他们应该各自遍历了一次A链表和B链表。那么他们走了m+n步后,不应该是在对方链表的结尾吗?为什么你说是在相交点呢?
两条链表在某个点之后合并为同一个链表。一旦两个指针相遇在某个节点,它们后续的路径就完全相同。因此,如果它们在某个点相遇,那一定是在相交的第一个节点。
第二遍写:
语法错误,if ... else ...
算法错误:如果两个链表没有交点,最后他们会在None相交,所以只要return pointA就好了。
这题留给二刷的时候再看,目前接触的题型太少了先尽量接触广一些。