今日题目:
解题思想:
- 虚拟头结点
在24. 两两交换链表中的节点此题中,同样需要设置虚拟头结点,它指向的是需要进行交换的两个节点的前一个位置。这样就可以用它来控制两个节点的交换。 需要注意循环的结束条件:因为cur指针指向的是两个交换节点的前一个节点位置,所以当cur指针后面没有节点,或者只有一个节点,都是循环停止的条件,即!cur.next || !cur.next.next
- 删除链表节点
第19题删除链表的倒数第n个节点,此题的关键点是如何找到要删除的节点的前一个位置。删除第n个节点,操作指针一定要指在第n-1个节点位置上 利用双指针,快指针先走n步,然后快慢指针同时走,直到快指针指向null停止,此时慢指针停在的位置就是倒数第n个节点,但是我们需要的是慢指针停在第n-1个节点,所以快指针应该在最开始多走一步,走n-1个位置。
- 链表相交
想要找出链表之间开始相交的位置,需要先计算出两条链表的长度,再让它们尾部对齐,再逐个对比节点所在的值是否相等。 题目不难,但是可以使用一些小技巧让代码更优雅:计算链表的这部分逻辑可以抽离出去,写一个函数专门用来计算链表长度;再者,为了使得代码逻辑不重复,可以让链表A永远是比较长的链表,如果不是的话就交换,这样操作链表对齐的时候只需要对A链表进行指针移动。
- 判断链表是否有环
使用快慢指针,分别定义fast和slow指针,从头结点触发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果fast和slow指针在中途相遇,则说明链表有环。 因为如果有环,fast指针必定先进入环中,如果fast指针与slow指针相遇,必定在环中相遇。
- 寻找环的入口
我们要求的是x,slow指针走过的节点数x+y fast指针走过的节点数x+y+n(y+z) n为fast指针在环内走了n圈才遇到slow指针,(y+z) 为一圈节点的个数 同时,fast指针走过的节点数 = 2*slow指针走过的节点数 即(x+y)*2 = x+y+n(y+z) 两边消掉一个(x+y):x+y=n(y+z) ,因为要求的是x, x=n(y+z)-y ,再将这个式子变形,得到x=(n-1)(y+z)+z 重点分析此等式,因为n是fast转的圈数。一定大于等于1,当n等于1的时候,得到等式x=z 。不管n等于多少,相遇点都在环入口位置。 所以,计算环的开始位置,就是计算z,可以记录上次快慢指针的相交位置,当快慢指针相遇的时候,让其中一个回到头结点,然后同速前进,再次相遇即为环开始的位置。
代码:
var swapPairs = function(head) {
if(!head || !head.next) return head
const dummyHead = new ListNode(0,head)
let pre = dummyHead
while(pre.next && pre.next.next) {
let node1 = pre.next
let node2 = pre.next.next
pre.next = node2
node1.next = node2.next
node2.next = node1
pre = node1
}
return dummyHead.next
};
var swapPairs = function(head) {
if(!head || !head.next) return head
const newHead = head.next
head.next = swapPairs(head.next.next)
newHead.next = head
return newHead
};
var removeNthFromEnd = function(head, n) {
const dummyHead = new ListNode(0, head)
let slow = fast = dummyHead
while(n--) {
fast = fast.next
}
fast = fast.next
while(fast){
slow = slow.next
fast = fast.next
}
slow.next = slow.next.next
return dummyHead.next
};
var getIntersectionNode = function(headA, headB) {
let curA = headA
let curB = headB
let lenA = getListLen(headA)
let lenB = getListLen(headB)
if(lenA < lenB) {
[curA, curB] = [curB, curA];
[lenA, lenB] = [lenB, lenA]
}
let i = lenA - lenB
while(i--) {
curA = curA.next
}
while(curA && curA !== curB) {
curA = curA.next
curB = curB.next
}
return curA
};
var getListLen = function(head) {
let len = 0
let cur = head
while(cur) {
len++
cur = cur.next
}
return len
}
var detectCycle = function(head) {
if(!head || !head.next) return null
let slow = head.next
let fast = head.next.next
while(fast && fast.next && fast !== slow) {
slow = slow.next
fast = fast.next.next
}
if(!fast || !fast.next) return null
slow = head
while(fast !== slow) {
slow = slow.next
fast = fast.next
}
return slow
};
总结:
真的好困啊啊啊啊啊明天继续
删除链表节点的关键是,操作要删除的链表的节点的上一个位置。删除倒数第n个节点,可以利用双指针的方式巧妙控制位置。 环形链表两个问题,一,判断是否有环,当快指针遇到了空,当然没有环。二,判断链表环的位置,利用数学公式推导,可以发现快慢指针相交位置到环入口处的距离,等于链表开始位置到环入口处的距离,所以可以在两快慢指针相交后,把慢指针放回头部,两节点同速移动,到下次相遇的位置就是环的入口位置。
这些方法要是我自己想真的很难想到,不得不说有些解题思路真是太妙了!!!终于追平进度啦~链表结束,哈希表我来咯
|