题目链接: 24. 两两交换链表中的节点
思路:
如图,其实不是这个顺序也可以,但要注意指针和元素之间的关系。
代码:
var swapPairs = function (head) {
let ret=new ListNode(0,head),tmp=ret;//这里定义ret是为了方便返回头结点。
while(tmp.next&&tmp.next.next){
let pre=tmp.next,cur=tmp.next.next;
tmp.next=cur;
pre.next=cur.next;
cur.next=pre;
tmp=pre;//注意这里,pre和cur已经交换了节点,所以要更新到pre
}
return ret.next;
};
复杂度分析:
时间复杂度:O(n)
题目链接: 19.删除链表的倒数第N个节点
思路:
1.两遍扫描 先看看有多少元素,然后算出sum-n得到往前遍历的次数,再删除。
2.双指针法 只需要一遍扫描
代码:
var removeNthFromEnd = function(head, n) {
let dummyhead=new ListNode(0,head);
let fast=slow=dummyhead;
let count=n+1;
while(count--){
fast=fast.next;
}
while(fast){
fast=fast.next;
slow=slow.next;
}
slow.next=slow.next.next;
return dummyhead.next;
};
复杂度分析:
时间复杂度:O(n)
题目链接: 160.链表相交
思路:
1.求两个链表长度(可以定义一个求长度函数)
2.算出长度差值move,并设置curA的指针移动move个单位(末尾元素对齐)
3.curA curB一起移动并且比较值的大小,若相等,则返回节点,遍历完了curA等于null说明没找到也可以直接返回。
代码:
var getlength= function(head){
let cur=head;
let length=0;
while(cur){
cur=cur.next;
length++;
}
return length;
}
var getIntersectionNode = function(headA, headB) {
let curA=headA,curB=headB,
lengthA=getlength(headA),
lengthB=getlength(headB);
if(lengthA<lengthB){
// 交换变量注意加 “分号” ,两个数组交换变量在同一个作用域下时
// 如果不加分号,下面两条代码等同于一条代码: [curA, curB] = [lenB, lenA]
[curA, curB] = [curB, curA];
[lengthA, lengthB] = [lengthB, lengthA];
}
let move=lengthA-lengthB;
while(move--){
curA=curA.next;
}
while(curA&&curA!=curB){
// if(curA===curB) return curA;
curA=curA.next;
curB=curB.next;
}
return curA;
};
问题:
语法问题:为什么代码里面有的函数有;,有的函数结束后不用写;?
还有js的分号问题,中间这个变量交换还不太懂为什么:
// 交换变量注意加 “分号” ,两个数组交换变量在同一个作用域下时
// 如果不加分号,下面两条代码等同于一条代码: [curA, curB] = [lenB, lenA]
复杂度分析:
时间复杂度:O(n + m)
空间复杂度:O(1)
题目链接: 142. 环形链表 II
思路:
1.判断有没有环
双指针法,让F每次移动2,S每次移动1,相当于产生一个F追S的相对运动(每次相对运动1),如果有环一定会相遇。
2.判断环的入口在哪
代码:
var detectCycle = function(head) {
if(!head || !head.next) return null;//一个或者0个元素没有环
let slow =head.next, fast = head.next.next;
while(fast && fast.next && fast!== slow) {//因为fast每次移动两个所以需要判断fast和fast.next都不为空,不然fast.next.next就没意义了
slow = slow.next;
fast = fast.next.next;
}
if(!fast || !fast.next ) return null;
slow = head;
while (fast !== slow) {//js的不等于号是这样写的吗
slow = slow.next;
fast = fast.next;
}
return fast;
};
涉及到删除头结点,或者是头结点位置变化的操作的时候,设置虚拟头结点可以比较方便的统一处理,而不用去分类讨论(lc24 19)
1.两两交换链表中的节点,用虚拟头结点可以方便返回头结点(因为后来头结点换位置了),其他的注意记录三个节点tmp,pre,cur,还有指针改变的逻辑和顺序。
2.删除节点,可以用双指针,F先走n+1,然后再一起走,最后F等于null时候删除。
3.循环链表,推导有点难,但是第二遍基本上背下来思路了。先判断有没有环再判断入口点。