链表
链表常用技巧大多数可以通过画图来更直观的解决。
206. 反转链表
题目描述
反转一个单链表。
例子1
Input: 1->2->3->4->5->NULL
output: 5->4->3->2->1->NULL
进阶:
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
思考
1 比较简单,直接反转就可以
参考实现1
实现1
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
// Input: 1->2->3->4->5->NULL
// Output: 5->4->3->2->1->NULL
// Runtime: 84 ms, faster than 67.00% of JavaScript online submissions for Reverse Linked List.
// Memory Usage: 40.6 MB, less than 37.61% of JavaScript online submissions for Reverse Linked List.
const resver = (head, newHead) => {
if (head === null) {
return newHead;
}
const temp1 = head.next;
head.next = newHead;
newHead = head;
head = temp1;
return resver(head, newHead);
};
var reverseList = function (head) {
let newHead = null;
return resver(head, newHead);
};
export default (head) => {
let newHead = null;
//return resver(head, newHead);
while (head) {
const temp1 = head.next;
head.next = newHead;
newHead = head;
head = temp1;
}
return newHead;
};
21. 合并两个有序链表
题目描述
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
例子1
Input: l1 = [1,2,4], l2 = [1,3,4]
output: [1,1,2,3,4,4]
例子2
Input: l1 = [], l2 = []
output: []
思考
1 比较简单
参考实现1
2 递归实现
参考实现2
实现1
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
function ListNode(val, next) {
this.val = val === undefined ? 0 : val;
this.next = next === undefined ? null : next;
}
// Runtime: 84 ms, faster than 92.56% of JavaScript online submissions for Merge Two Sorted Lists.
// Memory Usage: 40.8 MB, less than 10.66% of JavaScript online submissions for Merge Two Sorted Lists.
export default (l1, l2) => {
let newHead = new ListNode();
let head = newHead;
while (l1 && l2) {
let val;
if (l1.val <= l2.val) {
val = l1.val;
l1 = l1.next;
} else {
val = l2.val;
l2 = l2.next;
}
const temp = new ListNode(val);
newHead.next = temp;
newHead = temp;
}
if (l1) {
newHead.next = l1;
}
if (l2) {
newHead.next = l2;
}
return head.next;
};
实现2
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
function ListNode(val, next) {
this.val = val === undefined ? 0 : val;
this.next = next === undefined ? null : next;
}
const rescur = (l1, l2, newHead) => {
if (l1 && l2) {
let val;
if (l1.val <= l2.val) {
val = l1.val;
l1 = l1.next;
} else {
val = l2.val;
l2 = l2.next;
}
const temp = new ListNode(val);
newHead.next = temp;
newHead = temp;
rescur(l1, l2, newHead);
}
if (l1 && !l2) {
newHead.next = l1;
}
if (l2 && !l1) {
newHead.next = l2;
}
};
export default (l1, l2) => {
let newHead = new ListNode();
let head = newHead;
rescur(l1, l2, newHead);
return head.next;
};
24. 两两交换链表中的节点
题目描述
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
例子1
Input: head = [1,2,3,4]
output: [2,1,4,3]
例子2
Input: l1 = [], l2 = []
output: []
思考
1 比较简单
参考实现1
实现1
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
function ListNode(val, next) {
this.val = val === undefined ? 0 : val;
this.next = next === undefined ? null : next;
}
const rescrue = (pre, head) => {
if (head) {
let next = head.next;
if (!next) {
return;
}
pre.next = next;
head.next = next.next;
next.next = head;
rescrue(head, head.next);
}
};
// Runtime: 76 ms, faster than 79.57% of JavaScript online submissions for Swap Nodes in Pairs.
// Memory Usage: 39 MB, less than 12.95% of JavaScript online submissions for Swap Nodes in Pairs.
export default (head) => {
if (!head || !head.next) {
return head;
}
let pre = new ListNode();
const currentHead = pre;
rescrue(pre, head);
return pre.next;
};
160. 相交链表
题目描述
编写一个程序,找到两个单链表相交的起始节点。
例子1
Input: intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
output: 8
提示: 1 不能修改链表的结构
思考
1 本来想先反转A和B链表,然后从反转之后的开头开始寻找,但是提示不能修改链表结构,所以不行。
后来想起来龟兔赛跑,好像不能用
后来看了下题解,原来是使用两个指针,分别遍历A和B两个链表,当一个指针走到一个链表的末尾之后,指针重新指向另外一个链表的开头,这样到最后两个指针走过的距离就是相同的。
参考实现1
实现1
// Runtime: 128 ms, faster than 18.76% of JavaScript online submissions for Intersection of Two Linked Lists.
// Memory Usage: 46 MB, less than 77.97% of JavaScript online submissions for Intersection of Two Linked Lists.
export default (headA, headB) => {
let copyA = headA;
let copyB = headB;
let count = 0;
while (headA && headB && count < 3) {
if (headA === headB) {
return headA;
}
headA = headA.next;
headB = headB.next;
if (!headA) {
headA = copyB;
++count;
}
if (!headB) {
headB = copyA;
++count;
}
}
return null;
};
时间复杂度O(m+n) 空间复杂度O(1)
234. 回文链表
题目描述
请判断一个链表是否为回文链表。
例子1
Input: 1->2
output: false
例子2
Input: 1->2->2->1
output: true
思考
1 找到中间节点,然后使用栈对比就可以了
参考实现1
实现1
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {boolean}
*/
// Runtime: 100 ms, faster than 23.11% of JavaScript online submissions for Palindrome Linked List.
// Memory Usage: 42 MB, less than 65.81% of JavaScript online submissions for Palindrome Linked List.
export default (head) => {
let count = 0;
let copyHead = head;
while (head) {
++count;
head = head.next;
}
let half;
if (count % 2 === 0) {
half = count / 2 + 1;
} else {
half = Math.ceil(count / 2) + 1;
}
let curHead = copyHead;
const stack = [];
while (half > 1) {
--half;
stack.push(curHead.val);
curHead = curHead.next;
}
if (count % 2 !== 0) {
stack.pop();
}
while (curHead) {
if (curHead.val !== stack.pop()) {
return false;
}
curHead = curHead.next;
}
return true;
};
83. 移除链表中的重复元素
题目描述
移除链表中的重复元素。
例子1
Input: head = [1,1,2]
output: [1,2]
例子2
Input: head = [1,1,2,3,3]
output: [1,2,3]
思考
1 直接删除就可以了
参考实现1
实现1
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
// Runtime: 84 ms, faster than 94.39% of JavaScript online submissions for Remove Duplicates from Sorted List.
// Memory Usage: 40.7 MB, less than 24.89% of JavaScript online submissions for Remove Duplicates from Sorted List.
export default (head) => {
let copyHead = head;
while (head) {
const next = head.next;
if (!next) {
return copyHead;
}
if (head.val === next.val) {
head.next = next.next;
} else {
head = next;
}
}
return copyHead;
};
时间复杂度O(n),空间复杂度O(1)
328. 奇偶链表
题目描述
给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。
例子1
Input: 1->2->3->4->5->NULL
output: 1->3->5->2->4->NULL
例子2
Input: 2->1->3->5->6->4->7->NULL
output: 2->3->6->7->1->5->4->NULL
说明:
应当保持奇数节点和偶数节点的相对顺序。
链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推
思考
1 链接偶数和奇数就可以,不过细节很多,需要注意细节
参考实现1
实现1
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
// Runtime: 96 ms, faster than 36.86% of JavaScript online submissions for Odd Even Linked List.
// Memory Usage: 41.3 MB, less than 19.30% of JavaScript online submissions for Odd Even Linked List.
export default (head) => {
let copyOddHead = head;
if (!head) {
return head;
}
let copytEvenHead = head.next;
let temp = copytEvenHead;
while (copytEvenHead) {
const next = copytEvenHead.next;
if (!next) {
head.next = temp;
break;
}
head.next = next;
head = next;
copytEvenHead.next = head.next;
copytEvenHead = head.next;
if (!head.next) {
head.next = temp;
break;
}
}
return copyOddHead;
};
19. 删除链表的倒数第 N 个结点
题目描述
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?
例子1
Input: head = [1,2,3,4,5], n = 2
output: [1,2,3,5]
例子2
Input: head = [1], n = 1
output: []
思考
1 使用快慢指针先找出倒数第n个的位置,这里有个技巧,通过增加一个头结点,你会发现逻辑清晰很多。
参考实现1
实现1
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
function ListNode(val, next) {
this.val = val === undefined ? 0 : val;
this.next = next === undefined ? null : next;
}
// Runtime: 104 ms, faster than 11.59% of JavaScript online submissions for Remove Nth Node From End of List.
// Memory Usage: 39.9 MB, less than 91.59% of JavaScript online submissions for Remove Nth Node From End of List.
export default (head, n) => {
const tempHead = new ListNode();
tempHead.next = head;
head = tempHead;
const copyHead = head;
let p = head;
while (n > 0) {
--n;
p = p.next;
}
while (p && p.next) {
p = p.next;
head = head.next;
}
const temp = head.next;
head.next = temp.next;
return copyHead;
};
148. 排序链表
题目描述
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
进阶:你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
例子1
Input: head = [4,2,1,3]
output: [1,2,3,4]
例子2
Input: head = [-1,5,3,4,0]
output: [-1,0,3,4,5]
思考
1 直接使用归并排序就可以。
参考实现1
实现1
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
function ListNode(val, next) {
this.val = val === undefined ? 0 : val;
this.next = next === undefined ? null : next;
}
const merge = (l1, l2) => {
let head = new ListNode();
let p = head;
while (l1 && l2) {
if (l1.val <= l2.val) {
p.next = l1;
l1 = l1.next;
} else {
p.next = l2;
l2 = l2.next;
}
p = p.next;
}
if (l1) {
p.next = l1;
}
if (l2) {
p.next = l2;
}
return head.next;
};
// Runtime: 140 ms, faster than 86.37% of JavaScript online submissions for Sort List.
// Memory Usage: 54.6 MB, less than 37.62% of JavaScript online submissions for Sort List.
const sortList = (head) => {
if (head === null || head.next === null) {
return head;
}
let pre;
let slow = head;
let fast = head;
while (fast && fast.next != null) {
pre = slow;
slow = slow.next;
fast = fast.next.next;
}
pre.next = null;
let l1 = sortList(head);
let l2 = sortList(slow);
return merge(l1, l2);
};
export default sortList;