链表-反转链表

70 阅读2分钟

给定一个单链表的头结点pHead,长度为n,反转该链表后,返回新链表的表头。

image.png

方法1:转换数据结构-使用数组栈

链表用next连接,反转起来比较麻烦,但是数组就不一样了,比较简单,其中栈先进后出,正好把顺序给反转了,所以我们就使用数组构造栈来解决。

function ListNode(x){
    this.val = x;
    this.next = null;
}
function ReverseList(pHead)
{
    if(!pHead) return pHead;
    
   let stack = [];
   let cur = pHead;
   let newHead = new ListNode(-1);
   let node = newHead;
    while(cur) {
        stack.push(cur.val);
        cur = cur.next;
    }
     while(stack.length) {
         const top = stack.pop();
         node.next = new ListNode(top);
         node = node.next; 
     }
    return newHead.next;
}

方法2: 使用循环

比如链表123,以第一个节点12举例,如果反转,需要把2指向1,但是2本来是指向3的,所以我们不能直接改变1指向2,而是先把3存储起来,再把2指向1, 循环每个节点做这样的操作。

function ReverseList(pHead){
    if(!pHead || !pHead.next) return pHead;
    let pre = null
    let cur = pHead;
    
    while(cur) {
        const oldNext = cur.next;
        cur.next = pre;
        pre = cur;
        cur = oldNext;
    }
    return pre;
}

方法3:使用递归

思考递归的时,要试着找出最小问题的解决方式,再推到大问题,而不是尝试一层层的去执行进去。

既然是递归,参数就只有一个,代表某个节点。比如链表123,选取最小问题,反转12来看待,假设1是head, 2就是head.next,把2指向1,就是把head.next的next指向head,代码就是 head.next.next = head;

function ReverseList(head) {
  // head是4的时,这里就直接return了
  if(head === null || head.next === null) {
    return head;
  }
   /* 
     按例子执行,最后一次递归执行完head是3,从后往前,依次是2 1
   */
  const newHead = reverseList(head.next); 
  
  head.next.next = head; // 执行反转的逻辑
  head.next = null; // 反转最后一个节点head是1的时,我们上次把2指向了1,但是1还是执向2呢,所以把这个指向给删除掉。
  
  return newHead;
  
}