一、92 反转链表II
问题描述
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
解题思路
这个题和206反转列表那道题是类似的,只是这个题目限定了链表反转的范围而已,所以需要注意将反转后的链表拼接回原链表中。
1、虚拟节点+头插法
a、设置虚拟节点dmy指向原链表头节点,找到left前一个节点pre;
b、初始化cur指针指向left节点,使用头插法反转链表,令nex=cur.next,cur.next=pre.next,pre.next=cur;直到cur走到right指向的节点,反转结束;
c、因为right后面可能还有节点,所以需要令原left节点指向cur.next,使链表连接完整;
d、返回dmy.next。
具体代码如下:
/**
* @param {ListNode} head
* @param {number} left
* @param {number} right
* @return {ListNode}
*/
var reverseBetween = function(head, left, right) {
if(head==null||head.next==null||left==right) return head;
let dmy=new ListNode(0,head);
let pre=dmy;
let leftnode=head;
let i=left;
while(--i){ //找到left指向的节点
pre=pre.next;
leftnode=leftnode.next;
}
let cur=leftnode;
for(;left<=right;left++){ //链表反转
let nex=cur.next;
cur.next=pre.next;
pre.next=cur;
cur=nex;
}
//连接right后半部分,使链表成为一个整体
leftnode.next=cur;
return dmy.next;
};
2、迭代法
a、设置虚拟节点dmy方便之后返回结果;
b、初始化pre、cur、next节点,left指向的节点和left后一个节点,left后两个节点;
c、反转链表:cur.next=pre,pre、cur、nex后移,直到cur移动到right指向的节点,反转结束;
d、这里为了将链表连接为一个整体,还需要额外记住left指向节点和其前一个节点;
e、返回dmy.next。
具体代码如下:
var reverseBetween = function(head, left, right) {
if(head==null||head.next==null||left==right) return head;
let dmy=new ListNode(0,head);
let pre1=dmy;
let leftnode=head;
let i=left;
while(--i){
pre1=pre1.next;
leftnode=leftnode.next;
}
let pre=leftnode;
let cur=leftnode.next;
for(;left<right;left++){
let nex=cur.next;
cur.next=pre;
pre=cur;
cur=nex;
}
pre1.next=pre;
leftnode.next=cur;
return dmy.next;
};
二、141 环形链表
题目描述
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
解题思路
1、map或者set
具体思路:新设置一个map,然后循环链表,每次遍历到一个节点的时候,判断当前节点是否在map中存在,如果不存在就把当前节点加入map中,如果存在的话说明之前访问过此节点,也就说明了这条链表有环。
var hasCycle=function(head){
let map=new Map();
while(head){
if(map.has(head)) return true;
map.set(head,true);
head=head.next;
}
return false;
};
2、快慢指针
准备两个指针fast和slow,循环链表,slow指针初始也指向head,每次循环向前走一步,fast指针初始指向head,每次循环向前两步,如果没有环,则快指针会抵达终点,如果有环,那么快指针会追上慢指针。
var hasCycle=function(head){
let fast=slow=head;
while(fast&&fast.next){
slow=slow.next;
fast=fast.next.next;
if(slow==fast) return true;
}
return false;
};
3、特殊解法
这是在解答区看到的,很有意思,想记录一下。
var hasCycle = function (head) {
try {
JSON.stringify(head)
//不能循环引用对象;
} catch{
return true
}
return false
};
//标记法 给遍历过的节点打记号,如果遍历过程中遇到有记号的说明已环
const hasCycle = function(head) {
while (head) {
if (head.tag) {
return true;
}
head.tag = true;
head = head.next;
}
return false;
};
三、142 环形链表II
题目描述
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
解题思路
和141思路一样的,只是返回值变为节点而已。
1、map或set
var detectCycle = function(head) {
if(head==null) return null;
let cur=head;
let map=new Map();
while(cur){
if(map.has(cur)) return cur;
map.set(cur,true);
cur=cur.next;
}
return null;
};
2、快慢指针
这里有个数学公式的推导,我就不赘述了,直接贴一下大佬的解释:a=c+(n-1)(b+c)
var detectCycle = function(head) {
if(head==null) return null;
let fast=slow=head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(fast==slow) {
let slow=head;
while(slow!=fast){
slow=slow.next;
fast=fast.next;
}
return slow;
}
}
retur