一、链表
(一)题目
160. 相交链表(7.3)
- 利用集合,先遍历一个链表,将它的节点存到集合中。再遍历另一个链表,看集合中是否有相同节点,如果有,则返回。
- 递归法
206. 反转链表(7.3)
-
双指针迭代
利用链表指针pre和cur,改变链表的连接顺序。(改变顺序后,pre和cur都往前挪一步)
var reverseList = function(head) { let cur = head; let pre = null; let tmp = null; while(cur !== null){ tmp = cur.next; cur.next = pre; pre = cur; cur = tmp; } return pre; };
-
递归方法
暂时没有花时间了解
234. 回文链表
-
空间复杂度为O(n)的解法:读取链表节点的值放到数组中,再进行判断。
-
空间复杂度为O(1)的解法:
题解中比较多的是递归,另外还有快慢指针、找到链表中间节点再反转后半部分链表等方法。
21. 合并两个有序链表
感觉不难,双指针做法,会判断逻辑,但是不知道怎样合并数组。
(1)方法1:迭代
用ListNode(-1)设立一个指向头节点的节点,用移动指针指向两个链表中较小的节点。
(2)方法2:递归
2. 两数相加(7.5)
感觉逻辑乱了,进位在本次求和就加上了。
19. 删除链表的倒数第N个节点(7.5)
进阶:一趟扫描实现
双指针方法:由于我们需要找到倒数第N个节点, 设置双指针,快指针比满指针超前N个节点,当快指针到达链表末尾时,慢指针到达倒数第N个指针。
对我来说,链表题难的不是逻辑,而是怎样实现,比如设置哑节点、当前节点、快慢指针等。
var removeNthFromEnd = function(head, n) {
let dummy = new ListNode(-1,head);
let fast = dummy;
let slow = dummy;
while(n--){
fast = fast.next;
} //先向前n步
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next;
}
slow.next = slow.next.next;
return dummy.next;
};
24. 两两交换链表中的节点
//非递归方法
var swapPairs = function(head) {
if(head == null || head.next == null) return head;
const dummy = new ListNode(-1);
dummy.next = head;
let pre = dummy, cur = head;
while(cur !== null && cur.next !== null){
pre.next = cur.next;
cur.next = cur.next.next;
pre.next.next = cur;
pre = cur; //这一步很重要,移到后面需要两两交换的节点前面
cur = cur.next;
}
return dummy.next;
};
还有递归解法,没理解透彻。
const swapPairs = function (head) {
// 递归终止条件
if (head === null || head.next === null) {
return head;
}
// 获得第 2 个节点
let newHead = head.next;
// 将第 1 个节点指向第 3 个节点,并从第 3 个节点开始递归
head.next = swapPairs(newHead.next);
// 将第 2 个节点指向第 1 个节点
newHead.next = head;
return newHead;
}
92.反转链表II
一般不允许直接修改节点值,而是修改链表连接指向。
(二)链表题型总结
1. 操作单链表某个节点
需要找到链表中某个节点的位置。
通过快慢指针定位到想要操作的节点位置,先让快指针走k步,再让快慢指针一起向后移动。
2. 回文链表、环形链表类型
2.1 回文链表
a. 把链表的值放到数组中判断
b. 利用快慢指针找到中点、反转后半部分链表进行判断
c. 递归
2.2 环形链表
(1)判断是否是环形链表:
a. 把节点放到集合中,判断是否重复出现。
b. 快慢指针是否相遇,环形链表中快慢指针会相遇。
(2)环形链表II——返回链表入环的第一个节点
需要先找到相遇点,让两个节点分别从链表头和相遇点出发,两个节点的相遇点是环形链表的入口节点。
3. 链表排序、合并链表
//排序链表 自顶向下解法
const merge = (head1, head2) => {
const dummyHead = new ListNode(0);
let temp = dummyHead, temp1 = head1, temp2 = head2;
while (temp1 !== null && temp2 !== null) {
if (temp1.val <= temp2.val) {
temp.next = temp1;
temp1 = temp1.next;
} else {
temp.next = temp2;
temp2 = temp2.next;
}
temp = temp.next;
}
if (temp1 !== null) {
temp.next = temp1;
} else if (temp2 !== null) {
temp.next = temp2;
}
return dummyHead.next;
}
const toSortList = (head, tail) => {
if (head === null) {
return head;
}
if (head.next === tail) {
head.next = null;
return head;
}
let slow = head, fast = head;
while (fast !== tail) {
slow = slow.next;
fast = fast.next;
if (fast !== tail) {
fast = fast.next;
}
}
const mid = slow;
return merge(toSortList(head, mid), toSortList(mid, tail));
}
var sortList = function(head) {
return toSortList(head, null);
};