Java算法之单链表的全部翻转

一、LCR 024. 反转链表

题目描述:

给定单链表的头节点 head ,请反转链表,并返回反转后的链表的头节点。

示例1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例2:

 

输入:head = [1,2]

输出:[2,1]

首先来看思路:

思路一: 双指针

        迭代的写法

首先我们要明确的是反转链表就是要让节点两两之间的指向全部反转

由这样

变成这样

所以我们可以定义两个指针,pre和cur,其中cur指向的是next域需要改变指向的节点,per指向的是cur的前一个节点

就像这样:

所以就可以对这两个指针初始化了

ListNode per = null;

Listnode cur = head; 

下一步就是让cur节点的next指向per所指的节点,不过在更改指向之前,我们需要先记录一下,cur现在的下一个节点的位置,因为如果改变指向后我们就找不到cur的下一个节点了。我们创建一个temp指针指向cur的下一个节点 

改变指向的代码也就很好写了

            ListNode temp = cur.next;
            //调转当前节点的指向
            cur.next = pre;
            //将两个指针全部后移一位
            pre = cur;
            cur = temp;

这一步执行后指针的状态会变成这样

 

在执行一次上面代码后直接状态会变成这样

接下来只要不断地循环去遍历链表就可以啦,那么到什么时候为止呢,我们来画一下最终状态

好我们可以看到最后一次循环迭代完成后cur指向了空,而per刚好指向了原链表的前最后个节点,也是 反转完成后链表的头节点,那这样我们就清楚循环结束的条件和该返回的头结点是什么了

while(cur == null){...}

return pre;

好的现在我们已经把逻辑搞清楚了现在就可以写出,链表反转的全部代码了

    public ListNode reverseList1(ListNode head) {
        //指向需要改变指向节点的前一个结点
        //头节点的前一个节为null
        ListNode pre = null;
        //指向需要改变指向的节点
        ListNode cur = head;
        while(cur != null){//这个条件确保所有的节点全部调转指向
            ListNode temp = cur.next;
            //调转当前节点的指向
            cur.next = pre;
            //将两个指针全部后移一位
            pre = cur;
            cur = temp;
        }
        //最终cur指向了null
        //pre指向了原链表的最后一个节点也就是反转后列表的头节点
        return pre;
    }

                递归的写法 

 那我们能不能参照着迭代来写出递归的函数呢

 先给你你们看一下递归的代码

    public ListNode reverseList2(ListNode cur,ListNode pre) {
        if(cur == null){//递归出口,当cur指向null时,per刚好指向了最后一个节点
            return pre;
        }
        ListNode temp = cur.next;
        cur.next = pre;
        return reverseList2(temp,cur);
    }

OK很清楚的可以看出是比迭代的代码要少的 

首先理解这件事情是要怎么做的

这件事情其实可以分成两部分 左边部分(已经完成链表反转的部分)和右边(还未完成链表反转的部分)

只需要将右边还未完成反转的部分链表的第一个节点,指向左边链表的最后一个节点即可,然后左边的链表会增加一个节点,而右边链表会失去一个节点,直到右边链表为空了为止。

这样分析的话我们其实只需操作右边还未完成反转的部分链表的第一个节点和左边链表的最后一个节点就可以了,所以我们定义了一个反转的函数,作用就是完成右边还未完成反转的部分链表的第一个节点指向左边链表的最后一个节点的功能

   public ListNode reverseList2(ListNode cur,ListNode pre)

其中cur 代表右边还未完成反转的部分链表的第一个节点

       pre 代表左边链表的最后一个节点的功能

递归出口就是右边链表为空 就是

        cur==null

下面是箭头转向的代码

        ListNode temp = cur.next;
        cur.next = pre;

然后就该将现在的右边还未完成反转的部分链表的第一个节点,也就是cur.next,和左边链表的最后一个节点cur

思路二: 使用头插法

        开一条新的链表,将依次遍历链表,去除链表的值,并将其使用头插法,生成一条新的链表,并返回新链表的头结点

这个思路简单,代码如下

public ListNode reverseList(ListNode head) {
        if(head==null){
            return null;
        }
        ListNode newhead = new ListNode(head.val);
        head = head.next;
        while(head!=null){
            ListNode temp = new ListNode(head.val);
            temp.next = newhead;
            newhead = temp;
            head = head.next;
        }
        return newhead;
    }

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值