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

本文介绍了LeetCode 328题目的解题思路,通过改进算法,避免了额外的头结点存储和多余的判断,实现了更简洁的奇偶链表操作。分析了如何利用奇节点和偶节点的相邻关系优化遍历,并提供了C++和Java代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

翻译

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

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

你应该尝试就地完成。

程序应该在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;
    }
### Detectron2 使用过程中的常见问题与解决方案 #### 一、编译错误 当尝试编译 Detectron2 的自定义操作时,可能会遇到 `nvcc.exe` 编译失败的情况。具体表现为以下错误消息: ``` error: command 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.3\bin\nvcc.exe' failed with exit status 1 ``` 此问题是由于 CUDA 版本不兼容或者某些代码逻辑不符合当前环境所致[^3]。 **解决方法:** 可以修改相关源码文件以适配当前环境。例如,在路径 `detectron2/layers/csrc/nms_rotated/` 下的 `nms_rotated_cuda.cu` 文件中,注释掉可能导致冲突的部分代码片段。以下是具体的代码调整示例: ```cpp // 注释掉可能引发问题的代码段 /* if (condition) { // 可能存在版本差异的实现细节 } */ ``` 通过上述方式能够有效规避因 CUDA 工具链版本不同而导致的编译异常。 --- #### 二、CUDA 和 cuDNN 配置不当 在 Windows 系统上安装 PyTorch 或其扩展库(如 torch-scatter)并集成到 Detectron2 中时,可能出现 CUDA 或 cuDNN 不匹配的问题。典型表现形式为运行时报错提示找不到特定函数或动态链接库加载失败[^1]。 **解决策略:** 确认所使用的 CUDA 和 cuDNN 版本是否满足官方文档的要求,并重新构建依赖关系树。推荐按照以下步骤验证环境一致性: - 安装与目标框架相适应的基础组件; - 测试基础张量运算功能正常运作后再引入高级模块。 --- #### 三、模型推理阶段性能优化不足 对于大规模数据集上的实时处理需求而言,默认参数设置下的速度往往难以达到预期效果[^2]。 **改进措施:** 针对硬件资源特性定制化调优方案,比如启用混合精度训练(Mixed Precision Training),减少内存占用的同时提升计算效率;另外还可以考虑利用 TensorRT 进行进一步加速部署流程。 --- #### 四、多机分布式训练同步障碍 跨节点间通信延迟过高会显著降低整体收敛速率甚至造成死锁现象发生。 **应对之策:** 合理规划网络拓扑结构以及选用高效的集合通讯算法来最小化交互开销;同时也要注意检查防火墙规则以免意外阻断必要的端口连接请求。 --- ### 总结 以上列举了几类较为常见的 Detectron2 实践难题及其对应的处置建议。实际开发过程中还需依据具体情况灵活运用这些技巧加以克服困难。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值