2. Add Two Numbers
先初始化两个结点,一个用来做head,一个作为指引node不断向下延续的指针,初始化carry为0。当l1或l2或carry有一个存在时,就执行while循环。
- 需要注意的点有,在while循环一开始就应该先设置v1, v2为0. v1和v2是用来分别存放l1和l2的结点的值的。如果不将他们设为0,当输入为[5], [5]时,程序就会time limit exceeded。因为这时carry总是有值的,这个值并没有被存入linkedlist中,而是一直存在于carry里。
- 求出digit的值后,
n.next = ListNode(digit), n = n.next
不能写成n.val = digit, n = n.next
,n一开始是head,并且不需要为val赋值,直接将这个值设为ListNode结点类型就可以了
237. Delete Node in a Linked List
我们都知道删除一个结点,可以通过n.next = n.next.next
,这样删除的是n.next,那如果只给你n,要怎样将n自己删除?答案就是先将n.val = n.next.val
, 将n.val用n.next.val覆盖,这样就有了两个值重复的节点,然后用上边的语句将n.next删除就行了。这样做其实删除的并不是n,而是n.next,只是将n.next的值赋给了n而已。
21. Merge Two Sorted Lists
当l1和l2都存在时,进行while循环,如果l1 >= l2, 就将n.next = l1, l1 = l1.next, n= n.next
, 反之亦然。需要注意的是,等号可以和大于小于任意一个合并,意思就是当出现等于时,就一直连接l1或l2里等于的值,直到等于的值连接完了,再连接另一个List里等于的值。当while循环结束时,因为有可能l1,l2中期中一个依然没有连接完,所以用两个If语句连连接剩下的node
19. Remove Nth Node From End of List
这次是从linkedlist末尾,remove掉第n个元素。并且要求尽量在one pass内完成。
要remove掉一个元素,我们的思路就是找到这个元素的前一个位置. 用两个指针,都从dummy开始,先让指针runner走n步, 这时walker是从runner开始向前数的第n+1个元素,我们就形成了一个窗口。然后开始等速移动这两个指针,直到runner到了最后一个元素,此时walker就在我们想remove的元素的前一个位置。将walker.next = walker.next.next
就可以了
24. Swap Nodes in Pairs
交换相邻两个node, 不能仅交换他们的值。思路是要进行三次next重定向。以dummy->1->2->3->4为例:
- 要将1.next指向2.next,即3
- 要将2.next指向1
- 要将dummy.next指向2
思路的关键点在于要用一个临时指针来指向2,即dummy.next.next,这样做的原因是,当我们执行了第一个重定向时,就再也找不到2了,回不去了。所以要在执行第1个步骤时先将2用临时指针标记起来,留作之后使用
temp = dummy.next.next 标记
dummy.next.next = temp.next 步骤1
temp.next = dummy.next 步骤2
dummy.next = temp 步骤3
dummy = dummy.next.next
61. Rotate List
- 先数出list的长度,len从1开始,到最后一个节点停止。
- 对k进行mod,
k = k%len
,这样做是为了节省时间,提高效率,因为如果k==len,那结果就是原来的list。 - 得到新的k之后,用两个从head开始的指针,进行for循环,这里需要注意的点是:我们想要找到需要rotate的那段list,当循环
range(k)
次后,fast指针刚好来到需要rotate的list的前一个节点. 原因就是我们需要rotate k个节点,循环k次后,slow不变,依然在原来的位置,fast则正好和slow相差k+1个节点(包括他俩自己),这样就形成了一个窗口。 - 然后开始同时移动slow和fast, 直到fast来到最后一个节点。此时slow指向了需要rotate的list的前一个节点
-
newhead = slow.next, slow.next = None, fast.next = head
最后返回return newhead
83. Remove Duplicates from Sorted List
当head.next存在时,判断
if head.val == head.next.val: head.next = head.next.next
else: head = head.next
82. Remove Duplicates from Sorted List II
与上一题不同的地方在于,这道题要求将重复的结点都删去,一个都不留。此时我们就需要一个指针来指向第一个重复结点的前一个数字。当重复结点结束时,使得head指针指向重复结点的最后一个数字。这样通过pre.next = head.next
就可以把中间所有的重复结点都删掉了。需要注意的点有:
- 我们用一个bool类型的变量repeat来标记值是否重复,如果
head.val == head.next.val
我们就将repeat设为true,并向后移动head - 当head和head.next值不相等时,就要判断repeat是否为真,若为真,我们就将中间的结点删去,并将head向后移动一位,但注意, pre不能再向后移了,因为若向后移就和head重合了。最后把repeat设为false
- 当repeat不为真时,我们就直接向后移动head和pre
- 很重要的一点是,也是corner case, 那就是linkedlist里的节点值全都相等,也就是当while循环结束了,重复的值却依然都在,因为已经遍历到最后一个节点了。这是要多加一个if判断
if repeat
在while循环外部,如果while循环结束了repeat仍然为真,那我们就指行pre.next = head.next
把中间的重复结点都删掉,这点非常重要,很容易遗漏 - 最后返回
dummy.next
86. Partition List
要能知道这道题就是把原来的linkedlist划分为两个,一个比x值小,一个大于等于x的值,然后让第一个linkedlist指向第二个linkedlist,并将第二个linkedlist的最后一个元素指向空就可以了。
- 需要注意的点有,在将第一个linkedlist指向第二个的时候
pointer1.next = dummy2.next
, 这里一定要是dummy2.next
而不能是dummy
206. Reverse Linked List
用pre来标记head前边的节点,next标记head的下一个节点
while head:
next = head.next
head.next = pre
pre = head
head = next
return pre
需要注意的是: pre = None
,Pre要先初始化为空,每次循环开始要先标记head.next
92. Reverse Linked List II
这道题用上一道题做了subroutine,思路是先找到要reverse的第一个节点的前一个节点start,和最后一个节点的后一个节点end。这个地方画图会更明白一些。然后我们要做的就是对start和end之间的节点用上道题的方法进行reverse。
- 怎样找到start和end?
两个while循环,while m!=1:
找start,while n!= -1
找end。 - pre的初始化还是空吗?
不是了,pre的初始化应该是end,先把尾端连接起来 - reverse中间的节点时,循环结束条件是什么?
while head != end
,注意当这个循环结束时,我们还没有把首端连接起来,要在循环外部加上start.next = pre
- 找到start和end后,怎样找到要reverse的第一个节点?
head = start.next
, head就是我们要reverse的第一个节点
109. Convert Sorted List to Binary Search Tree
和105,106题有点像,先将linkedlist里的值取出来存到数组里,再根据数组来构造BST.
根:mid = len(list)/2, root = TreeNode(list[mid])
左子树:root.left = self.helper(list[:mid])
右子树:root.right = self.helper(list[mid+1:])
138. Copy List with Random Pointer
整体思路就是将linkedlist存入哈希表中
初始化一个hash table,老指针作为key,新指针作为value。先将linkedlist遍历一遍,存入新指针。
然后进行第二遍遍历,此时所有的node都存在hash table里了,
dic[p2].next = dic.get(p2.next) dic[p2].random = dic.get(p2.random) p2 = p2.next
循环结束后返回return dic.get(head)
141. Linked List Cycle
方法就是一个fast,一个slow指针,分别从头开始往后走,fast每次走两个结点,fast = fast.next.next
, slow每次走一个节点,slow = slow.next
,循环的判断条件是while fast and fast.next
。
如果两个指针相遇了,就证明有环,否则就没有环。
为什么两个指针一定会相遇呢?
因为如果环存在,fast先进入,slow后进入。两个指针都进入之后,可以把slow看做前边的那个指针,让fast在后边追赶它。因为两个指针此时都在环内,一个速度是另一个的两倍,所以一定会相遇。并且相遇时fast超过slow一圈
142. Linked List Cycle II
这道题的图片和思路来源:
http://www.cnblogs.com/hiddenfox/p/3408931.html
X为链表起点,Y为圆环起点,Z为slow和fast第一次相遇的点,abc为各段的长度,因为fast速度是slow的两倍,所以fast走过的路长也是slow的两倍,所以有等式2(a+b) = a + b + c + b
, 然后我们可以得出a = c
!!!这点非常有用。
现在我们想要找到Y, 我们可以让一个指针从x开始,像后走a步,但我们并不知道a有多远 ,也不知道c有多远,我们可以让slow从z出发,当slow和head相遇时,就证明他们都到达了Y点,分别走了相同的步数。此时指针指向的就是圆环起点。
- 如何将有环的链表变成单链表(解除环)?
- 如何判断两个单链表是否有交点?如何找到第一个相交的节点?
For1 在上一个问题的最后,将c段中Y点之前的那个节点与Y的链接切断即可。
For 2 如何判断两个单链表是否有交点?先判断两个链表是否有环,如果一个有环一个没环,肯定不相交;如果两个都没有环,判断两个列表的尾部是否相等;如果两个都有环,判断一个链表上的Z点是否在另一个链表上。
如何找到第一个相交的节点?求出两个链表的长度L1,L2(如果有环,则将Y点当做尾节点来算),假设L1
143. Reorder List
1,2,3,4,5,6
变成1,6,2,5,3,4
, 思路
- 将list分为两段:先用slow, fast两个指针找到list的中点,
slow.next = h2
用h2代表第二段list的head,然后使slow.next = None
- 构建一个reverse函数,将h2作为参数传进去,这个函数的作用时将传进来的list给reverse,并返回最后的头结点(注意应该返回pre,而不是head)
- 此时将h2插在h1和h1.next中间,并分别将h1和h2向后移动一个节点。循环判断条件是
while h1 and h2:
不需要返回任何东西,读题一定要读清楚了
147. Insertion Sort List
对Linkedlist进行插入排序,需要注意的有:
- 有序序列的最后一个node.next应该为空
- 每次从头开始扫描有序的List, 所以有
prepre = dummy
- 当
while prepre.next.val < cur.val
截止时,此时prepre.next并不一定就是pre,所以要将pnext = prepre.next
做记录 - 如果
cur.val>= pre.val
,就做自然连接,连接后分别更新cur和pre
148. Sort List
有两种方法:
- divide and conqure(merge and sort):新建三个虚拟node, n1,n2,n3,以head.val作为Pivot, 比pivot值小的节点,连在n1后边,与pivot值相等的节点,连在n2后边,比它大的结点,连在n3后边。然后再分别对n1, n3进行self.sortList()操作。最后将三段List连接起来
- Quick sort: 将List不断从中间分为两段,并将两段分别进行self.sortList(),然后再一段一段的进行连接。连接时要新建一个虚拟node,在两个list里,谁的值更小就连哪个。
445. Add Two Numbers II
Two stacks
234. Palindrome Linked List
reverse the first half while finding the middle
compare the reversed half with the second half
if fast: slow = slow.next
because the length might be odd, in this case, we don't need to compare the middle node, we need to skip it.