建议:用虚拟头结点,这样会方便很多。
题目链接/文章讲解/视频讲解:文章链接
题目链接:leetcode 24
题目描述:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
思路:创建虚拟结点,然后进行交换,注意顺序。把节点按顺序用 0 1 2 3 标清楚,在草稿纸上画画就清晰了。
代码:
var swapPairs = function (head) {
let ret = new ListNode(0, head) // 创建虚拟结点
let node = ret
while (node.next != null && node.next.next != null) {
let p = node.next
let q = p.next
p.next = q.next //1-3
q.next = p //2-1
node.next = q //0-2
node = p // 0到2,开始下一轮
}
return ret.next
};
时间复杂度:O(n)
空间复杂度:O(1)
这个真的很容易写错,就是谁先谁后,画画图就清楚多了。
node.next=q
q.next=p
p.next=q.next
// 一不小心写了个循环,得注意一下哈哈
建议:双指针的操作,要注意,删除第N个节点,那么我们当前遍历的指针一定要指向 第N个节点的前一个节点,建议先看视频。
题目链接/文章讲解/视频讲解:文章链接
题目链接:leetcode 19
题目描述:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
思路:让快指针先走n步,然后快慢指针一起走,当快指针走到最后一个结点的时候,慢指针刚好指向的是要删除结点的前一个结点。另外使用虚拟头结点可以很好地解决第一个结点的情况。
代码:
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
let ret = new ListNode(0,head)
let slow = fast = ret
while(n--) fast = fast.next
while(fast.next){
slow=slow.next
fast=fast.next
}
slow.next = slow.next.next
return ret.next
};
时间复杂度 O ( n ) O(n) O(n)
空间复杂度 O ( 1 ) O(1) O(1)
这道题注意一下:while(fast.next)我在while循环中就直接判断了,如果fast.next为空就不继续进行了,所以说,刚好slow指向的就是待删除结点的前一个结点。
建议:注意 数值相同,不代表指针相同。
题目链接/文章讲解/视频讲解:文章链接
题目链接:链表相交
题目描述:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
思路:拿到题就是想到的是暴力法,但是这个题,我看的真的很懵逼,第一个里面的1不相等下面的2又相等。实在是不明白,去看了视频。数值相同,不代表指针相同,这个我去理解了一下——题目的意思是让你找公共结点,**两个链表中有些结点是共用的,也就是地址一样,**让你找出共用的第一个结点。看到这句话明白了,也就是说,虽然例子1的值相等,但是1结点不是共用的!所以说值相等但是不一定是相交结点。
既然是地址相等,让两个链表末位对齐,那么如果有两个对齐的值相等,就能找到公共结点。
代码:
/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
// 求链表长度
var getListLen = function(head) {
let len = 0, cur = head;
while(cur) {
len++;
cur = cur.next;
}
return len;
}
var getIntersectionNode = function(headA, headB) {
let curA = headA,curB = headB,
lenA = getListLen(headA), // 求链表A的长度
lenB = getListLen(headB);
if(lenA < lenB) { // 让curA为最长链表的头,lenA为其长度
// 交换变量注意加 “分号” ,两个数组交换变量在同一个作用域下时
// 如果不加分号,下面两条代码等同于一条代码: [curA, curB] = [lenB, lenA]
[curA, curB] = [curB, curA];
[lenA, lenB] = [lenB, lenA];
}
let i = lenA - lenB; // 求长度差
while(i-- > 0) { // 让curA和curB在同一起点上(末尾位置对齐)
curA = curA.next;
}
while(curA && curA !== curB) { // 遍历curA 和 curB,遇到相同则直接返回
curA = curA.next;
curB = curB.next;
}
return curA;
};
这个题理解起来有点绕,在思路里全部都已经进行了展现
时间复杂度:O(n + m)
空间复杂度:O(1)
建议:算是链表比较有难度的题目,需要多花点时间理解 确定环和找环入口,建议先看视频。
题目链接/文章讲解/视频讲解:文章链接
题目链接:leetcode 142
题目描述:给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
思路:怎么确定题目中有环?
代码: