LeetCode 328 Odd Even Linked List(奇偶链表)(Linked List)(*)

简介: 版权声明:转载请联系本人,感谢配合!本站地址:http://blog.csdn.net/nomasp https://blog.csdn.net/NoMasp/article/details/50535947 翻译给定一个单链表,将所有的奇节点归为一组,偶节点紧随其后。
版权声明:转载请联系本人,感谢配合!本站地址:http://blog.csdn.net/nomasp https://blog.csdn.net/NoMasp/article/details/50535947

翻译

给定一个单链表,将所有的奇节点归为一组,偶节点紧随其后。

请注意我们现在谈的是奇节点而不是节点上的值。

你应该尝试就地完成。

程序应该在O(1)空间复杂度和O(nodes)时间复杂度下完成。

例如:
给定 1->2->3->4->5->NULL,
返回 1->3->5->2->4->NULL。

注释:
最后归类出来的奇节点和偶节点的相对位置应该和输入时一致。

第一个节点为奇节点,第二个节点为偶节点,以此类推……

原文

Given a singly linked list, group all odd nodes together followed by the even nodes. 

Please note here we are talking about the node number and not the value in the nodes.

You should try to do it in place. 

The program should run in O(1) space complexity and O(nodes) time complexity.

Example:
Given 1->2->3->4->5->NULL,
return 1->3->5->2->4->NULL.

Note:

The relative order inside both the even and odd groups should remain as it was in the input. 

The first node is considered odd, the second node even and so on ...

分析

寒假第一题,农村老家真的超冷……我想的思路可能不是太简洁,再加上考虑的不全面,导致不断的出错、调试、出错、调试……最终花了好久才完成,而代码已经谈不上简洁了。

ListNode* oddEvenList(ListNode* head) {
    if (!head || !head->next) return head;
    bool oddFlag = true;          
    ListNode* odd = head;
    ListNode* even = head->next;
    ListNode* oddHead = odd;
    ListNode* evenHead = even;
    head = head->next->next;      
    while (head) {
        if (oddFlag) {
            odd->next = head;
            odd = odd->next;
            oddFlag = false;
        }
        else {
            even->next = head;
            even = even->next;
            oddFlag = true;
        }
        head = head->next;
    }
    if (!oddFlag)
        even->next = NULL;
    odd->next = evenHead; 
    return oddHead;
}

过程叻大概是这样的:

1,判断是否为空,两种情况都返回head。
2,新建odd和even来不断遍历,和head一样,它们三个是会移动的。
3,oddHead和evenHead是不会动的,用于最后拼凑新的链表。
4,用isOdd来判断当前的节点是否是奇节点,不管是不是,它们的操作都是类似的。
5,最后的时候,如果是奇节点结尾的,那么可能偶节点最后一个会是多余的,所以需要将它干掉。
6,拼凑新的链表用于返回。

然而仔细想想呢,其实还有很大的改善空间,比如说:

既定义了oddHead还定义了evenHead,有一个很好的解决方案是:用head来作为oddHead。这样在返回的时候我们就可以直接返回head了,那么新的问题来了?之前我们是用的head来进行迭代的,那么现在呢?我们需要找到一种新的解决办法。

我们来回顾一下之前的算法:用head来遍历每一个节点,用一个bool变量来标志这个节点的性质(奇节点还是偶节点)。举个例子:

12345NULL

我们发现奇节点的下一个节点恰好就是偶节点的下一个节点(1的下一个节点应该是2的下一个节点,也就是3),而偶节点的下一个节点也恰好是奇节点是下一个节点。这样我们就可以只通过odd和even两个变量来遍历了,既省去了用来遍历的head,也省去了一个变量oddHead,同时还可以直接返回head,何乐而不为呢?

还记得上面我们用了这样一步吗?

if (!isOdd)
    even->next = NULL;
odd->next = evenHead; 

如果按照现在的思路,那么也完全不需要这个判断了,因为在求next的过程中,已经将该用NULL的地方设置成了NULL。

所以代码修改成:

ListNode* oddEvenList(ListNode* head) {
    if (!head) return head;    
    ListNode* odd = head;
    ListNode* even = head->next;
    ListNode* evenHead = even;   
    while (odd->next && even->next) {
        odd->next = even->next;
        odd = odd->next;    
        even->next = odd->next;
        even = even->next;
    }
    odd->next = evenHead;
    return head;
}

while循环中间的部分的顺序可不能颠倒了,只有更新了odd之后,才能将odd->next的设为even->next。

代码

C Plus Plus

/**
* Definition for singly-linked list.
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        if (!head) return head;
        ListNode* odd = head;
        ListNode* even = head->next;
        ListNode* evenHead = even;
        while (odd->next && even->next) {
            odd->next = even->next;
            odd = odd->next;
            even->next = odd->next;
            even = even->next;
        }
        odd->next = evenHead;
        return head;
    }
};

Java

updated at 2016/09/20
    public ListNode oddEvenList(ListNode head) {
        if (head == 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;
    }
目录
相关文章
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
|
存储 Java
|
存储 SQL 算法
LeetCode 题目 86:分隔链表
LeetCode 题目 86:分隔链表
|
Java 索引
Java List实战:手把手教你玩转ArrayList和LinkedList
【6月更文挑战第17天】在Java中,ArrayList和LinkedList是List接口的实现,分别基于动态数组和双向链表。ArrayList适合索引访问,提供快速读取,而LinkedList擅长插入和删除操作。通过示例展示了两者的基本用法,如添加、访问、修改和删除元素。根据场景选择合适的实现能优化性能。
340 0
|
Java 开发者 索引
Java List全攻略:从ArrayList到LinkedList,一网打尽!
【6月更文挑战第17天】Java List详解:ArrayList依赖动态数组,擅长随机访问和遍历,适合少次插入删除;LinkedList基于双向链表,插入删除高效,尤其在头尾操作,但随机访问慢。选择取决于应用场景,理解特性以优化代码。探索ArrayList与LinkedList,提升编程效率!
349 0
|
Java 索引
那些年,我们追过的Java List——ArrayList与LinkedList的爱恨情仇
【6月更文挑战第17天】ArrayList与LinkedList,Java List接口的双子星,各有千秋。ArrayList基于数组,随机访问快速,但插入删除慢;LinkedList用链表实现,插入删除高效,但索引访问慢。两者在爱恨情仇中教会我们权衡选择,成为编程旅程中难忘的记忆。 ```
180 0
|
存储 Java C++
Java List大揭秘:ArrayList vs LinkedList,谁才是真正的王者?
【6月更文挑战第17天】ArrayList和LinkedList是Java中实现List接口的两种方式。ArrayList基于动态数组,适合随机访问和遍历,内存紧凑,但插入删除元素特别是在中间时效率低。LinkedList以双向链表实现,擅长任意位置的插入删除,内存管理灵活,迭代高效,但随机访问性能差。选择使用哪种取决于具体应用场景。
235 0
|
C++ 容器
【C++进阶】深入STL之list:高效双向链表的使用技巧
【C++进阶】深入STL之list:高效双向链表的使用技巧
【经典LeetCode算法题目专栏分类】【第7期】快慢指针与链表
【经典LeetCode算法题目专栏分类】【第7期】快慢指针与链表
|
存储 SQL 算法
LeetCode 83题:删除排序链表中的重复元素【面试】
LeetCode 83题:删除排序链表中的重复元素【面试】