反转链表进阶
最近课程比较紧张,中秋放假休息了两天,回来继续刷算法题。链表翻转是个比较常见的类型,要吃透。
力扣第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题:重排链表
题目描述:
给定一个单链表 L:L0→L1→…→L**n-1→Ln , 将其重新排列后变为: L0→L**n→L1→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; } }