美文网首页
《剑指offer》(十五)-反转链表

《剑指offer》(十五)-反转链表

作者: 鼠小倩 | 来源:发表于2019-11-30 18:22 被阅读0次

反转链表

考点:链表

题目描述

输入一个链表,反转链表后,输出新链表的表头。

代码格式

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode ReverseList(ListNode head) {

    }
}
image.png

解题一—递归

1.思路
假设链表为[1,2,3,4,5]先迭代到链表末尾5,然后从5开始依次反转整个链表
如下图所示,先迭代待最后一位5,并且设置一个新的节点newList作为反转后链表的头结点,由于整个链表反转后的头就是最后一个数,所以newList存放的一直是反转后的头结点的地址,将head指向的地址赋值给head->next->next指针,并且一定要记得让head->next =NULL,也就是断开现在指针的链接,否则新的链表形成了环,下一层head->next->next赋值的时候会覆盖后续的值。依次反转。。


image.png

2.代码

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode ReverseList(ListNode head) {
         //判断链表为空或长度为一
        if(head==null||head.next==null){
            return head;
        }
        ListNode newList = ReverseList(head.next); //一直循环到链尾
        head.next.next = head; //翻转链表的指向
        head.next = null; //记得赋值NULL,防止链表错乱
        return newList; //新链表头永远指向的是原链表的链尾
    }
}

解题二—非递归-改变指针的位置

1.思路
(1) 题目所给的是单链表,反转后的链表应该为:最后一个结点指向倒数第二个,倒数第二个指向倒数第三个,......,第二个指向第一个,第一个指向null;
(2)知道了反转后各个结点指向哪之后,就需要开始调整每个结点的next指针。
(3)这就需要把结点挨个从链表上摘下来,做调整;
(4) 这个调整过程需要两个指针辅助:pre记录其前一个结点位置,好让该结点的next指针指向前一个结点,但是在指向前一个结点前需要用一个指针next记录后一个结点地址,避免结点丢失。

  • 以3个节点为例:
    pre指针,用于记录当前结点的前一个结点地址
    next指针,用于记录当前结点的下一个结点地址


    image.png

    2.代码

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode ReverseList(ListNode head) {
         //判断链表为空或长度为一
        if(head==null||head.next==null){
            return head;
        }
        ListNode pre=null;//初始化pre指针,用于记录当前结点的前一个结点地址
        ListNode next=null; //初始化next指针,用于记录当前结点的下一个结点地址
        while(head!=null){
            next=head.next;//为了防止链表断裂,先储存后一个节点
            head.next=pre;//保存完next,让当前结点与链表断开,就可以让head从指向next变成指向pre,即指向前一个节点,完成反转
            pre=head; // //pre指针指向当前结点
            head=next; // //head指向next(保存着原链表中head的下一个结点地址)
        }
        return pre;
    }
}

解题三-存储数组(代码有待提高)

1.思路
由于题目并没有要求必须原地反转,因此可以借助外部空间实现。这里可以将单链表储存为数组,然后按照数组的索引逆序进行反转。但是,此方式比较浪费空间,而且需要两次遍历,效率不占优势。
2.代码

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode ReverseList(ListNode head) {
         if(head == null)
        {
            return null;
        }
        List<Node> nodeList = new List<Node>();
        while (head != null)
        {
            nodeList.Add(head);
            head = head.Next;
        }

        int startIndex = nodeList.Count - 1;
        for (int i = startIndex; i >= 0; i--)
        {
            Node node = nodeList[i];
            if (i == 0)
            {
                node.Next = null;
            }
            else
            {
                node.Next = nodeList[i - 1];
            }
        }
        // 现在头结点是原来的尾节点
        head = nodeList[startIndex];
        return head;
    }
}

相关文章

网友评论

      本文标题:《剑指offer》(十五)-反转链表

      本文链接:https://www.haomeiwen.com/subject/enzcwctx.html