| 基本题型 | 题目链接 | 难度 |
|---|---|---|
| 合并两个有序列表 | 21. 合并两个有序链表 | ⭐ |
| 返回倒数第k个节点 | 剑指 Offer 22. 链表中倒数第k个节点 | ⭐ |
| 反转链表 | 剑指 Offer 24. 反转链表 | ⭐ |
| 区间反转 | 92. 反转链表 II | ⭐⭐⭐ |
| 两两交换链表中的节点 | 24. 两两交换链表中的节点 | ⭐ |
| k个一组翻转链表 | 25. K 个一组翻转链表 | ⭐⭐⭐ |
| 合并k个排序链表 | 23. 合并K个升序链表 | ⭐⭐ |
| 回文链表 | 234. 回文链表 | ⭐⭐ |
| 链表相交 | 160. 相交链表 | ⭐⭐ |
合并两个有序列表
- 创建一个节点
hail,并且使用cur指向它 - 然后进行循环,比较每次的点
list1和list2的值的大小,小的话,就接在cur的后面
- 然后每次循环
cur = cur.next - 跳出循环,判断各自链表中是否有存在值,如果存在的话,就让
cur指向那个有值的链表
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} list1
* @param {ListNode} list2
* @return {ListNode}
*/
var mergeTwoLists = function(list1, list2) {
let hail = new ListNode(0)
let cur = hail
while(list1 && list2){
if(list1.val < list2.val){
cur.next = list1
cur = cur.next
list1 = list1.next
}else{
cur.next = list2
cur = cur.next
list2 = list2.next
}
}
if(list1){
cur.next = list1
}
if(list2){
cur.next = list2
}
return hail.next
};
好像有递归的方法
返回倒数第k个节点
- 计数总共n个节点,然后使用for循环n-k
- 另外设置一个链表,让他先走k,然后两个同时到达终点
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} k
* @return {ListNode}
*/
var getKthFromEnd = function(head, k) {
// 17点09分
// 第一步:获取链表的总结点数
let cur = head
let count = 0
while(cur){
count++
cur = cur.next
}
cur = head
// count = 3 k = 1 2
for(let i = 0;i < count - k;i++){
head = head.next
}
return head
};
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} k
* @return {ListNode}
*/
var getKthFromEnd = function(head, k) {
let l2 = head
let l1 = head
while(k){
l2 = l2.next
k--
}
while(l2){
l2 = l2.next
l1 = l1.next
}
return l1
};
反转链表
- 首先设置一个
pre结点,表示前面的值 - 然后每次循环的话,就先保存
head.next,接着让head.next指向pre,然后pre变为head,然后head为tem
- 最后返回上一个结点就是
pre
\
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var reverseList = function(head) {
// 17点21分
let pre = null
while(head){
let tem = head.next
head.next = pre
pre = head
head = tem
}
return pre
// 17点23分
};
- 使用递归方法
- 递归结束
cur为null
- 每次
cur指向pre - 递归循环为(cur,next)
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var reverseList = function(head) {
// 使用递归
let rever = (pre,cur) => {
if(!cur)return pre
// 下一个数
let next = cur.next
// 当当前的数指向上一个数
cur.next = pre
return rever(cur,next)
}
return rever(null,head)
};
区间反转
- 拿到
left前面的点font和left对应的点tail - 拿到开始进行遍历
- 让
font连接right点,tail连接right+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} left
* @param {number} right
* @return {ListNode}
*/
var reverseBetween = function(head, left, right) {
// 21点25分
let newNode = new ListNode(0)
// 这样子方便计数
let cur = newNode
cur.next = head
// 做左到右的距离
let count = right - left
for(let i = 0;i < left - 1;i++){
cur = cur.next
}
// 在left前面的根,用来连接第right个结点
let font = cur
// 表示的作为翻转链表的最后一个结点,作为结尾用来连接第right+1个结点
let tail = cur.next
// 表示上一个数
let pre = cur.next
// 从左节点开始
let curr = pre.next
for(let i = 0;i < count;i++){
let next = curr.next
// 为上一个结点
curr.next = pre
pre = curr
curr = next
}
// tail连接right+1个结点
tail.next = curr
// font连接第right个结点
font.next = pre
return newNode.next
};
两两交换链表中的节点
- 首先一个
newNode - 每次循环确定有
cur和cur.next的存在
- 需要
pre、two、cur pre表示两个数的前面那个数,指向two,two表示两个数的第二个数,指向cur,cur表示两个数的第一个数,指向next
/**
* 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}
*/
var swapPairs = function(head) {
// 只有临近的两个点才要进行交换,如果没有两个点不用进行交换
let newNode = new ListNode(0)
newNode.next = head
let cur = head
let pre = newNode
while(cur && cur.next){
let next = cur.next.next
let two = cur.next
two.next = cur
pre.next = two
cur.next = next
pre = cur
cur = next
}
return newNode.next
};
k个一组翻转链表
- 建立一个函数用来进行翻转前后
- 对次数进行判断链是否够长
- 后续的遍历
/**
* 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} k
* @return {ListNode}
*/
var reverseKGroup = function(head, k) {
let rever = (head,tail) => {
// 指向前面的数
let pre = tail.next
let cur = head
while(pre !== tail){
let next = cur.next
cur.next = pre
pre = cur
cur = next
}
return [tail,head]
}
let hair = new ListNode(0)
hair.next = head
let pre = hair
while(head){
// 尾部
let tail = pre
// 查看剩余的长度是否大于等于k
for(let i = 0;i < k;i++){
tail = tail.next
if(!tail)return hair.next
}
// 下一个开始
let next = tail.next;
// 调换
[head,tail] = rever(head,tail)
// 把子链表接入原来的链表
pre.next = head
tail.next = next
pre = tail
head = tail.next
}
return hair.next
};
合并k个排序链表
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode[]} lists
* @return {ListNode}
*/
var mergeKLists = function(lists) {
//18点39分 平时的话是两个链表,所以会比较简单一些
//这道题目的给出的链表数目很多,所以需要考虑到每一个链表,而且必须考虑到每一个链表对总链表的数
//新建一个函数用来两个李安表进行互换
//把两个链表从小到大进行排序
var sort = function(list1,list2){
if(!list1)return list2
if(!list2)return list1
var cur1 = list1
var cur2 = list2
//有一个结束的话
var res = new ListNode(0)
var cur = res
//如果两个都存在的话,就进入下一步
while(cur1 && cur2){
//如果谁大的话,谁就赋值下一个
if(cur1.val < cur2.val){
var tem = cur1.val
cur1 = cur1.next
}else{
var tem = cur2.val
cur2 = cur2.next
}
var temNode = new ListNode(tem)
cur.next = temNode
cur = cur.next
}
if(cur1)cur.next = cur1
if(cur2)cur.next = cur2
return res.next
}
if(lists.length == 0) return null
var cur = lists[0]
var len = lists.length
//就是两两进行比较
for(let i = 1;i < len;i++){
cur = sort(cur,lists[i])
}
return cur
//19点06分 做是做出来,但是就是结果的性能比较低
};
回文链表
- 使用快慢指针,找出中间的值,并在这个过程中将前半部分进行反转,反转最后是首指针
pre - 通过判断
fast是否为null,判断是否奇数还是偶数
- 对反转的链表和
slow之后的链表进行一一判断
/**
* 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}
*/
var isPalindrome = function(head) {
// 23点47分
// 没有或者只有一个元素
if(!head || !head.next)return head
let pre = null,cur = head, fast = head,slow = head
while(fast && fast.next){
// 反转前半段的
slow = slow.next
fast = fast.next.next
cur.next = pre
pre = cur
cur = slow
}
// 如果是偶数的话,那么结果 fast刚好为null,奇数的话fast不为null
if(fast) slow = slow.next
while(slow){
if(pre.val !== slow.val)return false
pre = pre.next
slow = slow.next
}
return true
};
链表相交
- 可以说是跑完自己的赛道,跑到别人的赛道,然后比较公平
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
var getIntersectionNode = function(headA, headB) {
// 00点31分
// 通过两次遍历,不同的话走各自的路
let curA = headA
let curB = headB
while(curA !== curB){
curA = curA === null?hQeadB: curA.next
curB = curB === null?headA: curB.next
}
return curA
};