反转链表
迭代是使用两个指针从前往后,递归是从后往前。
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
* @return {ListNode}
*/
// 定义一个函数表达式
var reverseList = function(head) {
// 声明指针 -- 块级作用域
let pre = null;
let cur = head;
while(cur){
// 声明一个常量
let temp = cur.next;
// 反转指针
cur.next = pre;
// 移动指针
pre = cur;
cur = temp;
}
// 最后cur会指向null,所以返回pre.
// 如果是返回pre.next,就是除了最后一个元素的前面的链
return pre;
};
2、递归法
递归ppt演示
当反转链表的时候,是从最后一个节点开始反转的。
/**
* 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 reverseList = function(head) {
// 3、递归的结束:当把最后一个节点放入递归的时候,结束. head.next == nul
if(head == null || head.next == null){
return head
}
// 2、一直移动到链表最后,那个节点就是newHead
let newHead = reverseList(head.next)
// 1、单层递归逻辑,每层递归结束出来的head就是前一个节点
head.next.next = head
head.next = null
return newHead
};
92. 反转链表 II
- 定义一个虚拟头节点,因为头节点也有可能发生改变。可以避免复杂的讨论。
- 利用虚拟头节点,确定各个位置的指针。
- 将left到right之间的节点断开,并且利用206.反转链表进行反转。
- 最后将整个链连接起来,注意连接的顺序。
var reverseBetween = function(head, left, right) {
// 1、设置虚拟头节点
const dummyNode = new ListNode(-1);
dummyNode.next = head;
// 2、设置各个指针(pre leftNode rightNode cur)的位置
let pre = dummyNode;
// pre移动到left位置的前一个节点,需要移动left-1步。注意这里是从1开始计数的
for(let i=0;i<left-1;i++){
pre = pre.next;
}
let leftNode = pre.next;
// 设置rightNode的位置,将它从pre的位置移动right-left+1个位置
let rightNode = pre;
for(let i=0;i<right-left+1;i++){
rightNode = rightNode.next;
}
// 设置cur的位置
let cur = rightNode.next;
// 3、断开连接
pre.next = null;
rightNode.next = null;
// 反转链表
var reverse = function(head){
let pre = null,cur = head;
while(cur){
let temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
}
// 4、反转left到right的部分
reverse(leftNode);
// 5、重新连接链表
pre.next = rightNode;
leftNode.next = cur;
// 返回翻转后的链表
return dummyNode.next;
};