leetcode 链表反转及变形

1 最简单的链表反转

  1. Reverse Linked List
    链表反转一般会有递归与非递归的写法,递归写法代码简洁,看起来很酷,但是难以理解

1.一般写法

public ListNode reverseList(ListNode head) {
       if (head == null || head.next == null) {
            return head;
        }
        ListNode pre = head;
        ListNode cur = head.next;
        while (cur != null) {
            ListNode t = cur.next;
            cur.next = pre;
            pre = cur;
            cur = t;
        }
        head.next = null;
        return pre; 
    }

其实原理 很简单,改变指针方向即可。
容易犯错的点就是忽略了边界值以及最后head.next需要指向空,即末尾。

2. 扩展写法

也可以计算出点个数来反转

 private ListNode reverseList(ListNode head) {
        int length = 0;
        ListNode p = head;
        while (p != null) {
            length++;
            p = p.next;
        }

        ListNode listNode = reverseN(head, length);
        return listNode;


    }
    private ListNode reverseN(ListNode head, int length) {
        ListNode pre = null;
        ListNode cur = head;
        while (length > 0) {
            ListNode n = cur.next;
            cur.next = pre;
            pre = cur;
            cur = n;
            length--;
        }

        return pre;

    }

虽然这种写法没有第一种简洁,但是如果想反转的不是全部节点,而是前多少个节点,这种写法就显出威力了,只需要稍微变形即可。如果全部反转,那么头节点的Next指向Null,如果部分反转,只需要把next的节点指向其余的节点即可。

private ListNode reverseList(ListNode head) {
        int length = 0;
        ListNode p = head;
        while (p != null) {
            length++;
            p = p.next;
        }

        ListNode listNode = reverseN(head, 4);
        return listNode;


    }

    private ListNode reverseN(ListNode head, int length) {
        ListNode pre = null;
        ListNode cur = head;
        while (length > 0) {
            ListNode n = cur.next;
            cur.next = pre;
            pre = cur;
            cur = n;
            length--;
        }
        if (head != null) {
            head.next = cur;
        }

        return pre;

    }

3 递归

递归写法一般都特别美

3.1 正常反转

思路其实也挺简单,不要跳进循环中。
一般写递归会注意三个条件:
1) 终止条件
2) 返回值
3) 递推式

private ListNode reverseList(ListNode head) {
    if(head==null || head.next==null){
        return head;
    }
    ListNode last = reverseList(head.next);
    head.next.next=head;
    head.next=null;
    return last;
}

如上面这个,递推式即使原来的子问题,针对链表一般是指除当前要处理的元素之外的,因此一般都是node.next
终止条件即为空的时候
处理返回值。
除了递推之外的这个元素需要特别处理,假设后面已经是反转后的,那么再连接上当前的就是整个链表了。

3.2前 N个节点的反转

前N个节点的反转与之前的略微不同,主要区别是前面反转后的最后一个节点指向Null,代表结束
而这个最后一个节点指向其余的未反转的节点。
未反转的节点是当n==1时的next

ListNode next=null;
    private ListNode reverseN(ListNode head, int length) {
        if(length==1){
            next=head.next;
            return head;
        }
        ListNode tail = reverseN(head.next, length - 1);
        head.next.next=head;
        head.next=next;

        return tail;

    }

2. lintcode 92

反转从m到n的节点

public ListNode reverseBetween(ListNode head, int m, int n) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode pre = null;
        ListNode cur = head;
        while (m > 1) {
            pre = cur;
            cur = cur.next;
            m--;
            n--;
        }
        ListNode h = pre;
        ListNode tail = cur;
        while (n > 0) {
            ListNode t = cur.next;
            cur.next = pre;
            pre = cur;
            cur = t;
            n--;
        }
        if (h == null) {
            head = pre;
        } else {
            h.next = pre;

        }
        tail.next = cur;
        return head;
    }

如果用递归会比较难理解点

public ListNode reverseBetween(ListNode head, int m, int n) {
        if(m==1){
            return reverseN(head,n);
        }
        head.next= reverseBetween(head.next, m-1,n-1);
        return head;
    }

    ListNode sucessor = null;

    private ListNode reverseN(ListNode head, int m) {
        if (head == null || head.next == null) {
            return head;
        }
        if (m == 1) {
            sucessor = head.next;
            return head;
        }


        ListNode li = reverseN(head.next, m - 1);
        head.next.next = head;
        head.next = sucessor;
        return li;
    }

如果m=1,相当于反转从第1个到第n个,也就是说反转前n个,就是利用之前的算法。
如果m>1,比如revers(head,3,6)反转第三个到第6个,首先取1个元素后,那就是反转其余的第2个到第5个,即
revers(head.next,2,5),假设其余的2,5反转完成,原来的head保持不变,只需要把Head.next指向其余的即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值