Day4-链表,leetcode24,19,面试题 02.07,142
- 两两交换链表中的节点
- 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
var swapPairs = function (head) {
let ret = new ListNode(0, head), temp = ret
while(temp.next && temp.next.next) {
let cur = temp.next.next, pre = temp.next
pre.next = cur.next
cur.next = pre
temp.next = cur
temp = pre
}
return ret.next
}
// 递归版本
var swapPairs = function (head) {
if (head == null || head.next == null) {
return head;
}
let after = head.next;
head.next = swapPairs(after.next);
after.next = head;
return after;
};
- 删除链表的倒数第 N 个结点
- 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点
var removeNthFromEnd = function (head, n) {
// 创建哨兵节点,简化解题逻辑
let dummyHead = new ListNode(0, head);
let fast = dummyHead;
let slow = dummyHead;
while (n--) fast = fast.next;
while (fast.next !== null) {
slow = slow.next;
fast = fast.next;
}
slow.next = slow.next.next;
return dummyHead.next;
};
- 面试题 02.07. 链表相交,同:160.链表相交
- 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
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;
};
- 环形链表 II
-
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
-
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
-
不允许修改 链表。
// 两种循环实现方式
/**
* @param {ListNode} head
* @return {ListNode}
*/
// 先判断是否是环形链表
var detectCycle = function(head) {
if(!head || !head.next) return null;
let slow = head.next, 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;
};
var detectCycle = function(head) {
if(!head || !head.next) return null;
let slow =head.next, fast = head.next.next;
while(fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if(fast == slow) {
slow = head;
while (fast !== slow) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
return null;
};
总结
-
一般涉及到 增删改操作,用虚拟头结点都会方便很多, 如果只能查的话,用不用虚拟头结点都差不多。
-
链表的种类主要为:单链表,双链表,循环链表
-
链表的存储方式:链表的节点在内存中是分散存储的,通过指针连在一起。
-
链表是如何进行增删改查的。
-
数组和链表在不同场景下的性能分析。
-
链表的一大问题就是操作当前节点必须要找前一个节点才能操作。
参考&感谢各路大神
宝剑锋从磨砺出,梅花香自苦寒来。