24.两两交换链表中的节点:4指针
24.两两交换链表中的节点
交换相邻两个节点,不是改值是改链表指针物理位置
思路都差不多,只是做法些许不同
原则:知道要 操作两个节点 的 前一个指针
- 循环开始指针移动的规则:看一次循环结束,第二次循环开始指针在哪
- 每次进入循环时要完成指针的更新
- 技巧:以一个指针为定位更新,其他指针相对它变
4指针
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var swapPairs = function(head) {
let dhead = new ListNode(0, head) //先定义虚头
let pre = dhead // 每次循环时的虚拟头结点
let pre1 = null
let cur = null //cur指向要交换的后一个
let tmp = null //存cur的下一个
while(pre.next !== null && pre.next.next !== null) {
// 指针到位:
pre1 = pre //pre1指向虚拟头结点
pre = pre1.next //pre指向虚头下一个:要交换的前一个
cur = pre.next //cur指向要交换的后一个
tmp = cur.next //存cur的下一个,每次循环都要更新
pre1.next = cur //反转节点
cur.next = pre
pre.next = tmp
// 一次交换完后,pre变成下一次的虚拟头结点
}
return dhead.next
};
面试题 02.07. 链表相交
面试题 02.07. 链表相交
先求出两个链表的长度,计算出长度差,长的那个链表指针先前移长度差步-->让两个链表对齐
之后就可以同时后移,如果指针的值相等说明,找到交点,如果到最后指针都指向null了还没找到说明没有交点-->返回null
双指针
- 解构赋值一定要加
;
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
var getIntersectionNode = function(headA, headB) {
let curA = headA
let curB = headB
let lenA = 0
let lenB = 0
while (curA) { // 求A长度
lenA++
curA = curA.next
}
while (curB) { // 求B长度
lenB++
curB = curB.next
}
curA = headA // 回到开头
curB = headB
if (lenB > lenA) { // 让curA指向长
// let tmp = curB //交换
// curB = curA
// curA = tmp
// tmp = lenA
// lenA = lenB
// lenB = tmp
// 交换变量注意加 “分号” ,两个数组交换变量在同一个作用域下时
// 如果不加分号,下面两条代码等同于一条代码: [curA, curB] = [lenB, lenA]
[lenA, lenB] = [lenB, lenA];
[curA, curB] = [curB, curA];
}
let n = lenA - lenB
while (n--) {
curA = curA.next // curA先前移多出来的对齐
}
while (curA !== curB) { //一起移直到指向同一个
curA = curA.next
curB = curB.next
}
return curA
};
142. 环形链表 II
142. 环形链表 II
判断有没有环,无环返回空,有环返回环的入口(开始进入环的第一个节点)
- 判断有无环:快(fast 每次移两个),慢(slow 每次移一个)双指针,如果相遇就说明有环
- 如果没有环,快慢指针会一直向前走,永远不可能相遇
- 当有环时,快指针先进入环内转圈,慢指针进入后,快指针相对慢指针位移为
1,每次前进1追慢指针 - 所以两个指针相遇说明有环
- 返回环的入口
重点:
x = z + (n-1)圈,所以一个指针从相遇点,一个指针从起点开始,以相同速度移动,相遇的点为入口处
总结:
- 快(fast 每次移两个)慢指针(slow 每次移一个):相遇,说明有环
- 环入口为:一个指针从相遇点,一个指针从起点开始,以相同速度移动,相遇的点
快慢双指针:相遇有环、起点和相遇同走找入口
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var detectCycle = function(head) {
let fast = head //快慢指针初始都为头结点开始,快一次两个,慢一次一个
let slow = head
while (fast && fast.next) { ////因为fast先走,只判断它就行 避免操作空指针
fast = fast.next.next //fast一次两个
slow = slow.next //slow一次一个
if (fast === slow) { // 快慢指针相遇,说明有环
index1 = fast //相遇点开始
index2 = head //头结点
while (index1 !== index2) { //两指针相遇点为入口
index1 = index1.next
index2 = index2.next
} //出循环时相遇
return index1
}
}
return null //都遍历完了快慢指针还没相遇说明无环
};
2. 两数相加
2. 两数相加
注意:两个链表的结果给第三个链表用||,只要还有一个链表有元素(不为空)
空指针取值,如果为空取值为0,移动时也一定要判断空指针
最后一次如果还有进位,要记得加到链表最后
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
var addTwoNumbers = function(l1, l2) {
let l3 = new ListNode(0, null) // 定义新链表存结果,虚头
let p1 = l1; // 定义指针
let p2 = l2;
let p3 = l3;
let v1 = 0, v2 = 0, v3 = 0, val = 0
let carry = 0 // 进位
while (p1 || p2) { // 只要还有
v1 = p1 ? p1.val : 0 // 不为空取值,为空取0
v2 = p2 ? p2.val : 0
val = v1 + v2 + carry // 相加总值
v3 = val % 10 // 个位数
carry = Math.floor(val / 10) // 十位数,JS计算结果有小数
p3.next = new ListNode(v3, null) // 加入新链表
p3 = p3.next // 指针继续移动
if (p1) p1 = p1.next // 一定要判断空指针
if (p2) p2 = p2.next
}
if (carry) { // 如果最后一次计算结果还是有进位,加到最后
p3.next = new ListNode(carry, null)
}
return l3.next
};
83. 删除排序链表中的重复元素
- 删除结点肯定要使用虚拟头结点
- 注意判断空指针,保证不操作空指针
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var deleteDuplicates = function(head) {
let dhead = new ListNode(0, head) // 删除肯定要用虚头
let pre = dhead // 便于删除
let cur = pre.next // 遍历元素
while (cur && cur.next) {
if (cur.val === cur.next.val) { // 相等则删
pre.next = cur.next
cur = cur.next
} else {
pre = cur
cur = cur.next
}
}
return dhead.next
};