掘金团队号上线,助你 Offer 临门! 点击 查看详情
题目描述
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回反转后的链表。
示例1:
解题思路
两种方式: 因为两种方式都用到了虚拟头节点,也是俗称的哨兵,在这道题目中虚拟头节点的作用是方便对链表的特殊操作进行处理,所有有可能操作到链表头节点的操作,都可以设置一个虚拟头节点。
一:迭代法,上次给过反转链表的动态图示了,可以举一反三,这次口述步骤:
- 首先我们定义一个虚拟头节点,起名叫做ret,将它指向我们的真实头节点。
- 定义一个节点p = ret。
- 我们需要根据left找到带反转区域的头节点
- 接下来就是和206反转链表的思路一致了,只不过这里的循环终止条件需要依赖反转区域节点的总数,在循环结束时也不能直接返回pre,这样会丢失掉未反转部分的节点,所以区间反转过后,需要将原来的head头节点(也就是反转过后的尾节点)指针指向cur
- 后面就是执行我们定义的reverseList1函数,返回ret.next(虚头的next指向原链表头节点)
二: 递归:递归的函数用reverseList表示,递归方式符合进阶,只用了一次迭代,和206反转链表的不同点也是递归的终止条件,同样也需要注意下,不要丢失原链表节点。
解题代码
// 迭代封装的方法
var reverseList1 = function (head, n) {
let [pre, cur] = [null, head];
while (n--) {
[cur.next, pre, cur] = [pre, cur, cur.next];
}
head.next = cur;
return pre;
}
var reverseList = function (head, n) {
if (n === 1) return head;
let tail = head.next, p = reverseList(head.next, n - 1);
head.next = tail.next;
tail.next = head;
return p;
}
var reverseBetween = function (head, left, right) {
let cnt = right - left + 1;
let ret = new ListNode(0, head), p = ret;
while (--left) p = p.next;
// p.next = reverseList(p.next, cnt);
p.next = reverseList1(p.next, cnt);
return ret.next;
};
总结
最近学了链表这种数据结构,为了巩固,目前几篇都是专攻链表方面的算法题,如果文中有错误,忘指出。