我已经解决了这个问题:
给定单链表,将所有奇数节点组合在一起,然后是偶数节点。请注意,这里我们讨论的是节点编号,而不是节点中的值。
你应该尝试到位。该程序应该以O(1)空间复杂度和O(节点)时间复杂度运行。
示例:
Given 1->2->3->4->5->NULL, return 1->3->5->2->4->NULL.
我已经看过解决方案,但我不理解,我需要有人直观地解释问题的解决方案。
这是一个解决方案,但它是用Java编写的。我无法将指针操作可视化,有人可以为我画出什么东西吗?
public ListNode oddEvenList(ListNode head) {
if(head == null || head.next == null)
return head;
ListNode odd = head;
ListNode even = head.next;
ListNode evenHead = even;
while(odd.next != null && even.next != null){
odd.next = even.next;
odd = odd.next;
even.next = odd.next;
even = even.next;
}
odd.next = evenHead;
return head;
}
答案 0 :(得分:4)
假设你从一个单链表开始。它通常具有头部和尾部指针(这里左右倾斜),每个链接指向下一个。
在下图中,偶数节点为蓝色,奇数节点为灰色。
解决这个问题的一种方法是保持6个指针:
(这仍然是 O(1)。)
在上图中,原始列表(左侧的内容)位于右侧。处理后的偶数节点列表位于左上角,处理后的奇数节点列表位于左下角。
现在,虽然原始列表中仍有未处理的节点,但根据需要将当前节点移动到偶数或奇数列表。最后,只需将一个点的尾部链接到另一个的头部节点即可。将原始列表的头部和尾部指针设置为此结果列表,您就完成了。
答案 1 :(得分:4)
你已经得到了很好而详细的答案,所以我觉得有点愚蠢的发布这个,但是我需要一些时间来制作图纸,所以无论如何它都在这里。
我将解释您发布的算法,因为它可以直接在C ++中翻译(我以前虽然节点的"奇怪"是由它的值而不是它的位置决定的,并且需要使用指针指针来修改头部。
我只是在视觉上解释这个算法,我不会长篇大论如何实际上只是一个"压缩"有两个链表(一个用于奇数元素和偶数元素)以及如何处理指针的方式 正如评论中所述,有专门的书籍。
public ListNode oddEvenList(ListNode head)
{
//Check that there are AT LEAST TWO ELEMENTS
if (head == null || head.next == null)
return head;
//Initialize pointers
ListNode lastOdd = head;
ListNode lastEven = head.next;
ListNode firstEven = lastEven;
//Continue as long as there is at least two more elements
while (lastOdd.next != null && lastEven.next != null)
{
//Connect the last odd element with the element next to the
//last even one (such element is odd)
lastOdd.next = lastEven.next;
//Advance lastOdd to such element
lastOdd = lastOdd.next;
//Do the same for the even list, only inverting the roles
lastEven.next = lastOdd.next;
lastEven = lastEven.next;
}
//Now connect the last odd element with the first even element
//This join the two list together
lastOdd.next = firstEven ;
return head;
}
目视
//Initialize pointers
ListNode lastOdd = head;
ListNode lastEven = head.next;
ListNode firstEven = lastEven;
周期的第一次迭代
lastOdd.next = lastEven.next;
lastOdd = lastOdd.next;
lastEven.next = lastOdd.next;
lastEven = lastEven.next;
所有其他迭代
正如您现在可以想象的那样,循环重复,而 lastEven
和lastOdd
都有下一个元素,因为前者是后者之前的一个元素,在列表中至少两个未处理的元素。
一旦周期结束,唯一剩下的就是加入两个列表
答案 2 :(得分:2)
与其编写代码,我只是简单地给出一个基本概念的简要概要,希望它应该足够简单易懂。如果你开始绘制各种图表,我认为你可以在这里容易混淆。当基本概念非常简单时,没有必要在这里绘制复杂的图表
让我们定义一个“尾指针”是什么。尾指针是指向链表末尾的nullptr
的指针。这是一个双指针。
当单链表是空的时候:
node *head=0;
那就是问题所在的nullptr
:
node **tailptr= &head;
tailptr
指向链接列表的末尾,此时是头指针。
尾部指针允许你做什么?好吧,它允许您从head
开始,将新节点结束到列表的末尾,而不必找到它。您已经知道如何将元素添加到链表的开头。现在,您可以添加一个,就像这一样简单:
node *p=new node;
*tailptr=p;
p->next=0;
tailptr= &p->next;
如果你记住tailptr
指向列表末尾的nullptr
指针,那么这应该是完全合理的。您只需将nullptr
更改为指向在列表末尾插入的新节点即可。新节点的tailptr
,即nullptr
,因为它现在是新的最后一个节点,是新的尾指针。
为了实现这项家庭作业,您需要知道这一切。
您只需创建奇怪的偶数列表:
node *odd=0, *even=n0;
声明他们的尾指针:
node **tailptrs[2]={ &odd, &even};
int next_one=0;
然后,迭代原始的单链表,将每个条目追加到tailptrs[next_one]
,然后翻转它:next_one=1-next_one
。因此,当您浏览原始列表时,每个节点都会附加到奇数和偶数列表,并在两者之间交替。这甚至比您展示的基于Java的复杂逻辑更简单。
您需要做的最棘手的部分是记住节点的原始next
仍然是原始链接列表的一部分。一个技巧是更新每个tailptr
而不将当前节点的next
设置为nullptr
,但要等到原始单链接列表完全迭代完毕,然后简单地将两个最终尾部指针设置为nullptr
。
答案 3 :(得分:2)
想法是将奇数节点收集在一起(开始时)同时跟踪奇数和偶数指针。
void groupOddNode(){
Node o,e,p,q;
o= head;
p= head;
e= head.next;
while(p.next!= null && p.next.next!= null){
p=p.next;
q=p.next;
p.next = q.next;
q.next = e;
o.next = q;
e=q.next;
o=o.next;
}
}
例如,1-2-3-4-5-6-7-8-9
第一次迭代后: 1-3-2-4-5-6-7-8-9 (e指向2和 o指向3)
第二次迭代后: 1-3-5-2-4-6-7-8-9 (e指向2和 o指向5)
第3次迭代后: 1-3-5-7-2-4-6-8-9 (e指向2和 o指向7)
第四次迭代后: 1-3-5-7-9-2-4-6-8 (e指向2和 o指向9)
我希望它有所帮助:)
答案 4 :(得分:0)
我们使用两个指针p1和p2分别跟踪奇数和偶数节点。如果列表的长度为偶数,则在p2.next == null处停止,即p2到达最后一个节点时。
在这种情况下,p1位于最后一个节点旁边的节点中。例如
1 -> 2 -> 3 -> 4 -> null
| |
p1 p2
如果列表的长度为奇数,则在p2 == null处停止,即p1在最后一个节点中。
1 -> 2 -> 3 -> 4 -> 5 -> null
| |
p1 p2
我们可以观察到p1总是比p2低1步,我们必须让p1停在奇数列表的最后一个节点,然后才是p1.next = evenHead。也就是说,我们不能丢失奇数列表的末尾,即让p1 = null。
解决方案:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode oddEvenList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode odd = head;
ListNode even = head.next;
ListNode evenHead = even;
while (even != null && even.next != null) {
odd.next = even.next;
odd = odd.next;
even.next = odd.next;
even = even.next;
}
odd.next = evenHead;
return head;
}
}