单链表反转

单链表反转

package LinkListReview;

class ListNode {
    int val;
    ListNode next;

    public ListNode(int val) {this.val = val;}
}

/**
 * 题目描述:反转一个单链表。
 * -------------------------------------------
 * 示例:
 * 输入: 1->2->3->4->5->NULL
 * 输出: 5->4->3->2->1->NULL
 */

/*
思路:
使用双指针,一个指针用来遍历原链表 a,另一个用来指向带返回链表 b 的头节点
每遍历一个原链表的节点,就在 b 的头节点前面加一个节点
 */
class Problem1 {
    public ListNode reverseList(ListNode head) {
        ListNode newhead = null;   //待返回链表 b 的头节点,初始化成 null
        ListNode current = head;    //用来遍历链表 a 的指针

        //遍历链表 a,把 a 里的数据添加到 b 的头部,这其实就类似于最简单的在链表末尾追加元素一样,只不过现在是在链表头部追加元素了
        while(current != null) {
            ListNode temp = newhead;        //当前头
            newhead = new ListNode(current.val);    //一个新的头
            newhead.next = temp;    //新头指向旧头
            current = current.next;
        }

        return newhead; //返回新链表
    }
}

/**
 * 题目描述:反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
 * 说明:
 * 1 ≤ m ≤ n ≤ 链表长度。
 * ------------------------------------------------------------------------------
 * 示例:
 * 输入: 1->2->3->4->5->NULL, m = 2, n = 4
 * 输出: 1->4->3->2->5->NULL
 */

/*
思路:
首先是最简单的单链表的反转,然后再分析,可以把它想象成是一条线,我们把它切成三段,
一段是待反转前面的部分,一段是待反转后面的部分,最后一段是待反转的部分,
我们只需要把待反转的部分转过来,然后再与前面的两段缝合到一起即可
 */
class Problem2 {
    public ListNode reverseBetween(ListNode head, int m, int n) {
        ListNode newhead = null;    //反转部分的头
        ListNode newtail = null;    //反转部分的尾
        ListNode current = head;    //用来遍历原链表的指针
        ListNode leftLink = null;   //带反转部分左侧的链表
        int i = 1;

        if(m == n) return head;     //如果 m == n,那么说明没有要反转的部分,直接返回原链表

        //遍历原链表
        while(current != null) {
            if(i >= m && i <= n) {
                //添加新的头节点
                ListNode temp = newhead;
                newhead = new ListNode(current.val);
                newhead.next = temp;
                if(newtail == null) newtail = newhead;  //如果是第一次添加,那么该节点也是反转部分的尾节点
            }

            //记录一下待反转部分的左半部分,以便缝合
            if(i == m - 1) {
                leftLink = current;
            }

            //当反转完成之后进行缝合
            if(i == n) {
                if(m == 1) head = newhead;  //如果 m 是 1,那么待反转的左半部分就是空的,直接让原来的头等于现在的头即可
                if(m != 1) leftLink.next = newhead; //如果 m 不等于 1,那么就把左半部分和反转之后的链表缝合起来
                newtail.next = current.next;       //把反转之后的链表和右半部分缝合起来
            }

            i++;
            current = current.next;
        }

        return head;

    }
}

引申:

​ 链表反转可以借用双指针来完成,在双向链表中同样可以用这种方法,但双向链表有一种更快的方法,就是用两个指针,一个指向头,一个指向尾,然后两边同时向中间靠拢,互换里面存储的数据即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值