问题描述:
给定一个链表list, 如果: list = 1 调整之后1。 list = 1->2 调整之后1->2 list = 1->2->3 调整之后1->2->3 list = 1->2->3->4 调整之后1->3->2->4 list = 1->2->3->4->5 调整之后1->3->2->4->5 list = 1->2->3->4->5->6 调整之后1->4->2->5->3->6 list = 1->2->3->4->5->6->7 调整之后1->4->2->5->3->6->7 根据上面的规律, 调整一个任意长度的链表。
问题分析:
链表调整问题有两大做法 :
借助于数组等集合,来作第三方调整,然后将调整后的数组串成链表 该法适用于笔试 中,因为不涉及复杂的指针操作,便于想象与实现,有种作弊的嫌疑,但显然面试官并不想要这个答案, 调整指针,无需额外空间,这是用于面试 中的答案。 分析题意,可知有两种情况:
当链表长度为奇数时,L1L2L3L4R1R2R3R4 应调整成 L1R1L2R2L3R3L4R4 的形式 当链表长度为偶数时,L1L2L3L4R1R2R3R4R5 应调整成 L1R1L2R2L3R3L4R4R5 的形式 所以对于该题,有两种方法:
方法一:先将整条链表存入数组中,然后根据调整规律,对于 前 n/2 个元素,i 索引处的元素应存放在调整后数组的 2*i 处 ,对于后 n/2 个元素,i索引处的元素应存放在调整后数组的 (i-n/2)* 2+1 处。而奇数长度的链表最后一个元素直接加在最后即可。 举例:原数组为{1,2,3,4,5,6},调整后数组应为{1,3,2,4,5,6},每个元素对应的索引由{0,1,2,3,4,5}变成了{0,2,4,1,3,5} 最后将调整后的数组串成链表 方法二:用快慢指针法 找到中间位置,分成左右两个链表,然后合并 两个链表。具体合并方法见代码,有详细解释。
经验教训:
* 对于链表问题,两种通用解法的适用场景
* 方法一中调整数组也可不用额外数组,这便是**完美洗牌**问题
* 方法二链表的具体调整方式
代码实现
public static void relocate(Node head) {
if (head == null || head.next == null) {
return ;
}
ArrayList<Integer> list = new ArrayList<>();
Node curNode = head;
while (curNode != null) {
list .add(curNode.value);
curNode = curNode.next;
}
int [] num = new int [list .size()];
if ((list .size() & 1 ) == 0 ) {
for (int i = 0 ; i < list .size() / 2 ; i++) {
num[2 * i] = list .get(i);
}
for (int i = list .size() / 2 ; i < list .size(); i++) {
num[(i - list .size() / 2 ) * 2 + 1 ] = list .get(i);
}
}else {
for (int i = 0 ; i < list .size() / 2 ; i++) {
num[2 * i] = list .get(i);
}
for (int i = list .size() / 2 ; i < list .size() - 1 ; i++) {
num[(i - list .size() / 2 ) * 2 + 1 ] = list .get(i);
}
num[list .size() - 1 ] = list .get(list .size() - 1 );
}
head.value = num[0 ];
Node cur = head;
for (int i = 1 ; i < num.length; i++) {
Node newNode = new Node(num[i]);
cur.next = newNode;
cur = newNode;
}
}
public static void relocate (Node head) {
if (head == null || head.next == null ) {
return ;
}
Node slow = head;
Node fast = head.next;
while (fast.next != null && fast.next.next != null ) {
slow = slow.next;
fast = fast.next.next;
}
Node mid = slow;
Node rHead = slow.next;
mid.next = null ;
Node lHead = head;
mergeList(lHead, rHead);
}
public static void mergeList (Node lHead, Node rHead) {
Node lCur = lHead;
Node rCur = rHead;
while (lCur.next != null ) {
Node rNext = rCur.next;
rCur.next = lCur.next;
lCur.next = rCur;
lCur = rCur.next;
rCur = rNext;
}
lCur.next = rCur;
}