描述
将给定的单链表 L\ L L: L0→L1→…→Ln−1→LnL_0→L_1→…→L_{n-1}→L_ nL0→L1→…→Ln−1→Ln
重新排序为:L0→Ln→L1→Ln−1→L2→Ln−2→…L_0→L_n →L_1→L_{n-1}→L_2→L_{n-2}→…L0→Ln→L1→Ln−1→L2→Ln−2→…
要求使用原地算法,不能只改变节点内部的值,需要对实际的节点进行交换。
方法一
解法1:创建一个集合 简单粗暴
package Test;
/*
@CreateTime 2021/9/26 11:05
@CreateBy cfk
重排链表
参考:https://blog.nowcoder.net/n/6eeeca0a37344b1dbb5a9ac82381812e
*/
import java.util.ArrayList;
import java.util.List;
public class Demo01A {
public static void main(String[] args) {
Demo01A demo01A = new Demo01A();
ListNodeA listNode1 = new ListNodeA(1);
ListNodeA listNode2 = new ListNodeA(2);
ListNodeA listNode3 = new ListNodeA(3);
ListNodeA listNode4 = new ListNodeA(4);
listNode1.next = listNode2;
listNode2.next = listNode3;
listNode3.next = listNode4;
demo01A.reorderList(listNode1);
}
public void reorderList(ListNodeA head) {
if (head == null) return;
List<ListNodeA> list = new ArrayList<>(); //创建一个数组存储结点方便操作
while (head != null) {
list.add(head);
head = head.next; //遍历所有的结点 存储在数组中
}
int i = 0;
int j = list.size()-1;
//两个指针 一个从头开始 一个从尾开始遍历
while (i < j) {
list.get(i).next = list.get(j);
i++;
if (i == j) break; //当两个指针指向同一个位置 说明元素已经全部遍历完了 (这一步可以省略 没必要)
list.get(j).next = list.get(i);
j--;
}
//把最后一个结点指向null 否则它会指向4
//因为前面 它会再赋值一次 然后退出循环
list.get(i).next = null;
head = list.get(0);
}
}
class ListNodeA {
int val;
ListNodeA next;
ListNodeA(int x) {
val = x;
next = null;
}
@Override
public String toString() {
return "ListNodeA{" +
"val=" + val +
'}';
}
}
方法二
解法2: 分链表分成两半, 左边从小到大,右边从大到小 然后再依次读取组成新的链表
package Test;
/*
@CreateTime 2021/9/26 11:05
@CreateBy cfk
重排链表
参考:https://blog.nowcoder.net/n/6eeeca0a37344b1dbb5a9ac82381812e
*/
public class Demo01B {
public static void main(String[] args) {
Demo01B demo01B = new Demo01B();
ListNodeB listNode1 = new ListNodeB(1);
ListNodeB listNode2 = new ListNodeB(2);
ListNodeB listNode3 = new ListNodeB(3);
ListNodeB listNode4 = new ListNodeB(4);
listNode1.next = listNode2;
listNode2.next = listNode3;
listNode3.next = listNode4;
demo01B.reorderList(listNode1);
}
public void reorderList(ListNodeB head) {
//如果遇到没有元素或者只有俩个元素程序直接返回
if (head == null || head.next ==null) {
return;
}
//否则把链表分成两半,左边从小到大 右边从大到小
//设置两个指针一个一次移动一位 一个一次移动两位
//这样当快的指针移动到最后时 通过慢指针的位置确定链表的中间值
ListNodeB slow = head;
ListNodeB fast = head.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNodeB mid = slow.next; //把链表分为左右两份 左边比右边大1
slow.next = null;
System.out.println("没有反转的链表="+head);
ListNodeB newHead = reverseList(mid);//把后半截链表反转
//====================重点 方法一:合并两个数组================
//此方法比较好理解
/* ListNodeB temp = new ListNodeB(0); //创建一个第三方数组 最后把数据保存在这里面
ListNodeB tail = temp;
boolean flag = true;
//合并两个链表
while (head != null && newHead != null) {
if (flag) {
tail.next = head;
head = head.next;
flag = false;
}else {
tail.next = newHead;
newHead = newHead.next;
flag = true;
}
tail = tail.next;
}
//把head中剩下的全部元素添加到链表
while (head != null) {
tail.next = head;
head = head.next;
tail = tail.next;
}
//把newHead中剩下的全部元素添加到链表
while (newHead != null) {
tail.next = newHead;
newHead = newHead.next;
tail = tail.next;
}
System.out.println(temp);*/
//===================重点==================
//===================重点方法二==================
ListNodeB tmp = head; //保存头结点 否则后面找不到了
while(newHead != null){
ListNodeB temp = newHead.next; //保存右边数据的下一位数据
newHead.next = tmp.next; //让右边链表第一位指向左边链表第二位
tmp.next = newHead; //让左边链表第一位指向右边链表第一位
tmp = newHead.next; //把指针指向下一位
newHead = temp; //指针向后移动
}
// System.out.println(head);
//===================重点==================
}
//反转链表
public static ListNodeB reverseList(ListNodeB head) {
if (head.next == null) {
return head;
}//如果链表只有一个元素直接返回链接即可
ListNodeB tail = head; //创建一个尾节点保存原链表头节点
head = head.next; //让头指针后移一位
tail.next = null; //把后面的链表置空
while (head != null) {
ListNodeB tmp = head.next; //创建一个临时变量存储头结点的下一个节点 避免在操作时被删除了
head.next = tail; //让头结点下一位指向尾结点
tail = head; //把尾结点作为头结点
head = tmp; //最后重新定位头结点
}
System.out.println("被反转的链表为="+tail);
return tail;
}
}
class ListNodeB {
int val;
ListNodeB next;
ListNodeB(int x) {
val = x;
next = null;
}
@Override
public String toString() {
return "ListNodeB{" +
"val=" + val +
", next=" + next +
'}';
}
}
注意:希望能看到本文的人, 都能耐心看懂,本人算法也是小白菜,在刚开始看这道题的时候,我做题思路是创建两个新的链表,先把旧链表反转保存在一个新的链表中,然后再读一个原链表一个反转链表这样执行,最后直到两个链表的元素相等停止。自己琢磨了很久也没能实现,就去看网上别人写的答案理解。
最后硬着头发看了很久才能理解,对于这些指针使用,感觉挺陌生了,但是等你真正理解了,你就会发现不过如此,不要照搬代码,搬运别人的代码一定要加上自己的理解,学习的人加油啊!!!感谢您的阅读!!!