微信小程序日历组件技术架构解析:从日期计算到插件化设计
2026/6/7 19:52:39
对前端开发者而言,学习算法绝非为了“炫技”。它是你从“页面构建者”迈向“复杂系统设计者”的关键阶梯。它将你的编码能力从“实现功能”提升到“设计优雅、高效解决方案”的层面。从现在开始,每天投入一小段时间,结合前端场景去理解和练习,你将会感受到自身技术视野和问题解决能力的质的飞跃。------ 算法:资深前端开发者的进阶引擎
给你一个链表,删除链表的倒数第n个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]示例 2:
输入:head = [1], n = 2 输出:[1]示例 3:
输入:head = [1,2], n = 1 输出:[1]提示:
sz1 <= sz <= 300 <= Node.val <= 1001 <= n <= sz本题的核心挑战在于“倒数第N个”这个定位要求。单链表无法逆向回溯,因此必须通过正向遍历来找到这个特定位置。一个关键的边界情况是删除的可能是头节点,这需要我们仔细处理。
本题主要有两种主流思路,双指针(快慢指针)法是最优解。
L。L - n + 1。L - n的位置),执行删除操作。next指向head。这是处理链表删除问题的常用技巧,可以优雅地统一处理删除头节点和非头节点的情况,避免复杂的条件判断。fast和slow都指向哑节点。fast指针先向前移动n步。此时,fast和slow之间相隔n个节点。fast和slow,直到fast到达链表的末尾(fast.next为null)。此时,slow恰好指向待删除节点的前一个节点。因为fast和slow始终保持n的间距。slow.next = slow.next.next。dummy.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 * @param {number} n * @return {ListNode} */varremoveNthFromEnd=function(head,n){// 1. 第一次遍历:计算链表长度letlength=0;letcurrent=head;while(current!==null){length++;current=current.next;}// 2. 计算要删除节点的正数位置consttargetIndex=length-n;// 3. 处理删除头节点的特殊情况if(targetIndex===0){returnhead.next;}// 4. 第二次遍历:找到目标节点的前一个节点current=head;for(leti=0;i<targetIndex-1;i++){current=current.next;}// 5. 执行删除操作current.next=current.next.next;returnhead;};/** * 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} */varremoveNthFromEnd=function(head,n){// 1. 创建哑节点,其next指向原头节点constdummy=newListNode(0,head);// 2. 初始化快慢指针letfast=dummy;letslow=dummy;// 3. 快指针先走 n 步for(leti=0;i<n;i++){fast=fast.next;}// 4. 快慢指针同步前进,直到快指针到达链表末尾while(fast.next!==null){fast=fast.next;slow=slow.next;}// 循环结束时,slow指向待删除节点的前一个节点// 5. 删除节点slow.next=slow.next.next;// 6. 返回新头节点(哑节点的next)returndummy.next;};| 实现方案 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 |
|---|---|---|---|---|
| 两次遍历法 | O(L), L为链表长度 | O(1) | 思路直观,易于理解和实现 | 需要遍历链表两次,效率非最优;处理头节点删除需额外判断 |
| 双指针法(哑节点) | O(L), L为链表长度 | O(1) | 只遍历一次,效率高;代码统一简洁,哑节点技巧避免了头节点的特殊判断;面试和工程中的首选方案 | 引入了额外的哑节点,但对空间复杂度无影响,逻辑上稍需理解 |