反转链表进阶

最近课程比较紧张,中秋放假休息了两天,回来继续刷算法题。链表翻转是个比较常见的类型,要吃透。

 

力扣第92题:题目描述:反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

说明:1 ≤ m ≤ n ≤ 链表长度。

示例:

输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL

思路:

用指针记录要反转区间的首尾节点,在写一个反转局部区间m到n的函数,在将反转后的链接起来

    public static ListNode reverseBetween(ListNode head, int m, int n) {

        if (m == n) return head;
        //创建头结点
        ListNode pHead = new ListNode(0);
        pHead.next = head;
        ListNode tail = pHead;
        //找到需要反转那一段的前一个节点
        for (int i = 1; i < m; i++)
            tail = tail.next;
        //局部反转链表的新起点
        ListNode nextHead = tail.next;
        ListNode pre = null;
        ListNode next = null;
        //反转n到m这一段,即反转n-m+1个节点
        for (int i = 0; i <= n - m; i++) {
            next = nextHead.next;
            nextHead.next = pre;
            pre = nextHead;
            nextHead = next;
        }
        //pre即为局部反转的链表头节点
        tail.next = pre;
        //找到反转链表的最后一个节点
        while (pre.next != null) {
            pre = pre.next;
        }
        //链接起来
        pre.next = next;
        return pHead.next;
    }

 

力扣第25题:k个一组反转链表

题目描述:

给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序。

示例:

给定这个链表:1->2->3->4->5

当 k = 2 时,应当返回: 2->1->4->3->5

当 k = 3 时,应当返回: 3->2->1->4->5

说明:

  • 你的算法只能使用常数的额外空间。
  • 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

思路:用指针记录需要反转部分你的头尾节点,写一个局部反转的函数,每k个反转一次,不够K个就返回

public static ListNode reverseKGroup(ListNode head, int k) {
       if(head==null||head.next==null||k<=1)
           return head;
       ListNode currentNode = head;
       //获取k个元素的首尾节点
        for(int count=1;count<k;count++){
            currentNode = currentNode.next ;
            //不够k个就返回
            if(currentNode==null)
                return head;
        }
        ListNode next = currentNode.next;
        //对局部链表进行反转
        reverse(head,currentNode);
        //递归接着每K个反转一次
        head.next = reverseKGroup(next,k);
        return currentNode;
    }

 public static ListNode reverse(ListNode head,ListNode tail){
        if(head==null||head.next==null)
            return head;
        ListNode pre = null;
        ListNode next = null;
        while(pre!=tail){
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return head;
    }

 

力扣第143题:重排链表

题目描述:

给定一个单链表 LL0→L1→…→L**n-1→Ln , 将其重新排列后变为: L0→L**nL1→L**n-1→L2→L**n-2→…

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例:

给定链表 1->2->3->4, 重新排列为 1->4->2->3.
给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.

思路:寻找到链表的中间节点,将链表分为两段,将后半部分反转,在将两个链表合并

 public static void reorderList(ListNode head) {
        if (head == null || head.next == null)
            return;
        ListNode p1 = head;
        ListNode p2 = head;
        //寻找到链表的中间节点
        while (p2.next != null && p2.next.next != null) {
            p1 = p1.next;
            p2 = p2.next.next;
        }
        //将链表分为两段
        p2 = p1.next;
        p1.next = null;
        p1 = head;
        //将后半段链表进行反转
        ListNode pre = null;
        ListNode next = null;
        ListNode head2 = p2;
        while (head2 != null) {
            next = head2.next;
            head2.next = pre;
            pre = head2;
            head2 = next;
        }
        p2 = pre;
        //合并两个链表
        ListNode next1;
        ListNode next2;
        while (p2 != null) {
            next1 = p1.next;
            next2 = p2.next;
            p1.next = p2;
            p2.next = next1;
            p1 = next1;
            p2 = next2;
        }
    }

 

posted @ 2019-09-15 12:22  曾聪聪  阅读(405)  评论(0编辑  收藏  举报