- 获取链表中心节点
/**
* 当链表节点为偶数时,都返回前一个节点
* @param head
* @return
*/
private static ListNode endOfFirstHalf(ListNode head) {
if(head == null) return head;
ListNode fast = head;
ListNode slow = head;
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
}
System.out.println("half Val is "+slow.val);
return slow;
}
/**
* 可选择的,建议使用
* @param head
* @return
*/
private static ListNode endOfFirstHalfNew(ListNode head){
if (head == null) {
return null;
}
ListNode slow = head;
ListNode fast = head;
ListNode prev = null;
while (fast != null && fast.next != null) {
prev = slow;
slow = slow.next;
fast = fast.next.next;
}
// 当链表节点为偶数时,可以选择要返回的是链表前一个节点还是后一个节点
if (fast == null) {
// 链表长度为偶数,slow 指向后一个中间节点
return prev;
} else {
// 链表长度为奇数,slow 指向中间节点
return slow;
}
}
reverseList-反转链表-循环/迭代版本
public ListNode reverseList(ListNode head) {
ListNode pre =null;
ListNode cur = head;
ListNode next;
while(cur!=null){
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
reverseList-反转链表-后序遍历 递归版本
public ListNode reverseList2(ListNode head) {
// 因为下面要取head.next.next 所以head.next不能为空 可不要直接以head不为空作为递归结束条件哦
if(head == null || head.next == null){
return head;
}
ListNode last = reverseList2(head.next);
head.next.next =head;
head.next = null;
return last;
}
reverseListN-反转链表的前n个节点
其实就是在反转全部链表的基础上,将反转部分的后续节点定义为tailNode。将head.next =null 改为head.next = tailNode;
// 反转全部链表
ListNode tailNode = null;
public ListNode reverseList2(ListNode head) {
// 因为下面要取head.next.next 所以head.next不能为空 可不要直接以head不为空作为递归结束条件哦
if(head == tailNode || head.next == tailNode){
return head;
}
ListNode last = reverseList2(head.next);
// 后序执行反转
head.next.next =head;
head.next = tailNode;
return last;
}
// 反转链表前n个节点
ListNode tailNode = null;
public ListNode reverseListN(ListNode head,int n) {
// 找到tailNode
if(n == 1){
tailNode == head.next;
return head;
}
ListNode last = reverseListN(head.next,n-1);
// 后序执行反转
head.next.next =head;
head.next = tailNode;
return last;
}
reverseBetween-反转链表的left到right个节点-递归写法
如果left为1 就是求上文“反转前n个节点 ” 故有以下代码:
private ListNode reverseBetween1(ListNode head,int left ,int right) {
if(left == 1){
// 如果left=1 就变成了反转前right个节点 直接套用前面的reverseN
return reverseN(head,right);
}
// 如果left不等于1 就继续--
head.next = reverseBetween1(head.next,left-1,right-1);
return head;
}
reverseBetween-反转链表的left到right个节点-递归写法
只遍历一次,直接指定到对应位置,重点关注while循环的部分
public ListNode reverseBetween(ListNode head, int left, int right) {
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode pre = dummy;
int i = 0;
while (pre != null && i < left - 1) {
pre = pre.next;
i++;
}
ListNode cur = pre.next;
ListNode next;
int k = 0;
while(k < right-left){
// 每次把后一位插入前面
next = cur.next;
cur.next =next.next;
next.next = pre.next;
pre.next = next;
k++;
}
return dummy.next;
}
reverseKGroup-K个一组反转链表-递归+递归
借助上文反转前N个的reverseN,每次从head走k次找到下一次反转的起点b,反转前k找到newHead,返回之前递归反转从b开始的前k个节点
public ListNode reverseKGroup(ListNode head, int k) {
if (Objects.isNull(head)) return null;
ListNode b = head;
//b已经指向了第k+1个元素
for (int i = 0; i < k; i++) {
if (null == b) return head;
b = b.next;
}
//反转前k个
ListNode newHead = reverseN(head,k);
// 每次就把原来的头节点的next指向下一次翻转的结果,下次反转从b开始
head.next = reverseKGroup(b, k);
return newHead;
}
reverseKGroup-K个一组反转链表-递归+迭代
public ListNode reverseKGroup(ListNode head, int k) {
if (Objects.isNull(head)) return null;
ListNode a = head, b = head;
for (int i = 0; i < k; i++) {
if (null == b) return head;
b = b.next;
}
//此时b已经指向了第k+1个元素,开始反转a-b
ListNode newHead = reverseFromAToB(a, b);
// 每次就把原来的头节点的next指向下一次翻转的结果
a.next = reverseKGroup(b, k);
return newHead;
}
// 反转从a节点到b节点的迭代写法,对应前文left到right的递归写法
// 返回的应该为b节点的前一个节点
public ListNode reverseFromAToB(ListNode a, ListNode b) {
ListNode pre = null, cur = a;
while (cur != b) {
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
reverseFromAToB 反转从A节点到B节点
// 返回的应该为b节点的前一个节点
public ListNode reverseFromAToB(ListNode a, ListNode b) {
ListNode pre = null, cur = a;
while (cur != b) {
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}