【链表】
一、单链表的倒数第 k 个节点:
✔ 要求:只遍历一遍,链表有多长未知
LeetCode19
链接:
19.删除链表的倒数第N个结点
题目:
思路:
因为没有给头结点,我们就先定义一个哑结点,作为链表的头结点。
要删除倒数第n个结点,就要先找到倒数第n+1个结点x,然后再用x.next = x.next.next删掉倒数第n个。
封装一个找倒数第k个结点的函数,传入头结点和k。
先定义两个指针p1和p2都指向头结点,先让p1走k步,然后p1和p2一起走,直到p1===null,即两个指针一起走了n-k步,所以p2就指向了正数第n-k+1个结点,即为倒数第k个
🌟 链表注意点:
1️⃣ 设链表有n个结点,倒数第k个结点,就是正数第n-k+1个结点
2️⃣ 链表最后都会接一个空指针
代码:
/**
* 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}
*/
var removeNthFromEnd = function(head, n) {
// 还是先定义一个哑结点
const dummy = new ListNode(-1)
// 把哑结点跟链表连上,连在链表之前
dummy.next = head
// 要删除倒数第n个结点,就是要先找到倒数第n+1个结点
let x = findEnd(dummy, n+1)
// 删除那一个结点
x.next = x.next.next
return dummy.next
};
var findEnd = function(head, k) {
// 先定义p1和p2同时指向头结点
let p1 = head
let p2 = head
// 先让p1走k步
for(let i=0; i<k; i++) {
p1 = p1.next
}
// p1 和 p2 一起走n-k步,这样p2就是指向了n-k+1个节点,即倒数第k个节点
while(p1 !== null) {
p1 = p1.next
p2 = p2.next
}
return p2
}
二、单链表的中点
✔ 要求:只遍历一遍,链表有多长未知
LeetCode876
链接:
876.链表的中间结点
题目:
思路:
【快慢指针】:
慢指针走一步,快指针走两步,当快指针走到链表末尾时,慢指针就走到了链表的中点
注意:
这里可以继续前进的条件是,当前快指针和当前快指针的下一个结点都非空 -> 当有两个中间结点时,找出来的是后一个
👉 如果题目要求在两个中间结点的时候,返回前一个中间结点,此时快指针可以前进的条件改为:当前快指针的下一个结点和当前快指针的下下一个结点都非空
代码:
/**
* 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 middleNode = function(head) {
// 快慢指针
let slow = head, fast = head
while(fast !== null && fast.next !== null) {
// 慢指针走一步,快指针走两步
slow = slow.next
fast = fast.next.next
}
return slow
};
写在最后:
学校突然宣布放假了
的确不大喜欢计划被打乱的感觉
那就重新规划吧