第一题:
题目描述:
给你单链表的头结点 head
,请你找出并返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
来源:力扣(LeetCode)
链接:力扣
解题思路:
刚接触关于单链表的算法题,是按照之前数组的常规思维去做,当输出 head.length 的时候才发现了错误,因为单链表无法通过访问下标拿到元素,因此可以通过遍历元素存储到数组中,然后通过遍历获取 数组和单链表 的长度,通过 IndexList.length / 2 的位置拿出元素。
看到有大佬对代码进行了优化,运用了双指针,主要思路为:定义两个指针 slow 与 fast 同时遍历链表。slow 一次走一步,fast 一次走两步;当 fast 到达链表的末尾时,slow 必然位于中间。
补充一个小知识:
向下取整:Math.floor()
向上取整:Math.ceil()
只删除小数,不向上/下舍入:Math.trunc()
var middleNode = function(head) {
// 将链表转换为数组
let List = [head];
while(List[List.length-1].next != null) {
// 追加元素从而得到数组长度
List.push(List[List.length-1].next)
}
return List[Math.trunc(List.length / 2)];
};
双指针法:
var middleNode = function(head) {
slow = fast = head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
};
此方法链接:https://leetcode.cn/problems/middle-of-the-linked-list/solution/lian-biao-de-zhong-jian-jie-dian-by-leetcode-solut/
第二题:
题目描述:
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
来源:力扣(LeetCode)
链接:力扣
解题思路:
单链表的题太致命了,因为要删除倒数的元素,而 .next 是从前向后遍历头节点。
因此定义在倒数第n个元素之前的 那个元素为 pre_n,并让快指针比慢指针先走 n-1 步,在慢指针开始走的第一步时 便到达了所要删除的那个元素的位置。
此时,跳过那个元素,存储了 慢指针之前所遍历的元素之外(pre_n内),让pre_n.next 是 left.next,就成功跳过了那个元素。如果是删除第一个元素则直接返回 left.next
var removeNthFromEnd = function(head, n) {
// 定义倒数第 n 个结点 的前一个结点
let pre_n = null;
// 定义慢指针,用于找到要删除的元素,返回其之后的部分
let left = head;
// 定义快指针,用于遍历整个链表,比慢指针先走n-1步
let right = head;
// 以 [1,2,3,4,5] n=4 为例
for(let i=1; i<=n-1; i++) {
right = right.next;
// 1 [2,3,4,5] 2 [3,4,5] 3 [4,5]
// console.log(i, right);
}
// 如果不是删除最后一个元素
while(right.next != null) {
// 前一个结点的值为 left 的之前一次的值
pre_n = left; // [1,2,3,4,5]
left = left.next; // [2,3,4,5]
right = right.next; // [5]
}
// 如果删除是第一个元素
if(pre_n == null) {
return left.next; // [2,3,4,5]
}
else {
// 跳过 倒数第n个结点
pre_n.next = left.next;
}
return head;
};