(每日一练C++)143. 重排链表

给定一个单链表 L 的头节点 head ,单链表 L 表示为:

L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

输入:head = [1,2,3,4]
输出:[1,4,2,3]
示例 2:

输入:head = [1,2,3,4,5]
输出:[1,5,2,4,3]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reorder-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
public:
    void reorderList(ListNode *head) {
        if (head == nullptr) {
            return;
        }
        vector<ListNode *> vec;
        ListNode *node = head;
        while (node != nullptr) {
            vec.emplace_back(node);
            node = node->next;
        }
        int i = 0, j = vec.size() - 1;
        while (i < j) {
            vec[i]->next = vec[j];
            i++;
            if (i == j) {
                break;
            }
            vec[j]->next = vec[i];
            j--;
        }
        vec[i]->next = nullptr;
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/reorder-list/solution/zhong-pai-lian-biao-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

### C++ 链表重排算法详解 链表重排是一种常见的数据结构操作,其目标是将单向链表重新排列成特定的形式。以下是基于提供的参考资料以及专业知识的实现方法。 #### 1. 算法核心逻辑 为了完成链表重排任务,可以采用以下三步策略: - **找到链表中点**:通过快慢指针技术定位到链表的中间节点[^2]。 - **反转后半部分链表**:将链表从中点拆分为前后两个子链表,并将后半部分链表反转[^3]。 - **交替合并前半部分和反转后的后半部分**:按照题目要求依次连接前半部分和后半部分的节点。 #### 2. 示例代码实现 下面是完整的 C++ 实现: ```cpp #include <iostream> using namespace std; // 定义链表节点结构体 struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(nullptr) {} }; // 打印链表函数 (用于调试) void printList(ListNode* head) { while (head != nullptr) { cout << head->val << "->"; head = head->next; } cout << "nullptr" << endl; } // 寻找链表中点 ListNode* findMiddleNode(ListNode* head) { ListNode *slow = head, *fast = head; while (fast && fast->next) { // 快指针每次移动两步,慢指针每次移动一步 slow = slow->next; fast = fast->next->next; } return slow; // 当快指针到达终点时,慢指针正好位于中点 } // 反转链表 ListNode* reverseList(ListNode* head) { ListNode* prev = nullptr; ListNode* curr = head; while (curr) { ListNode* tempNext = curr->next; curr->next = prev; prev = curr; curr = tempNext; } return prev; } // 合并两条链表 void mergeLists(ListNode* l1, ListNode* l2) { while (l1 && l2) { ListNode* tmp1 = l1->next; ListNode* tmp2 = l2->next; l1->next = l2; if (!tmp1) break; // 如果第一条链已经结束,则停止 l2->next = tmp1; l1 = tmp1; l2 = tmp2; } } // 主要功能:重排链表 void reorderList(ListNode* head) { if (!head || !head->next) return; // 特殊情况处理 // Step 1: 找到链表中点 ListNode* mid = findMiddleNode(head); // Step 2: 断开链表并将后半部分反转 ListNode* secondHalfStart = mid->next; mid->next = nullptr; // 切断前半部分和后半部分之间的链接 secondHalfStart = reverseList(secondHalfStart); // 反转后半部分 // Step 3: 合并前半部分和反转后的后半部分 mergeLists(head, secondHalfStart); } int main() { // 创建测试链表 1 -> 2 -> 3 -> 4 ListNode* head = new ListNode(1); head->next = new ListNode(2); head->next->next = new ListNode(3); head->next->next->next = new ListNode(4); cout << "原始链表:" << endl; printList(head); // 调用重排函数 reorderList(head); cout << "重排后的链表:" << endl; printList(head); return 0; } ``` #### 3. 关键点解析 - 使用快慢指针寻找链表中点能够有效减少时间复杂度至 O(n)。 - 对于链表的操作,务必注意边界条件(如空链表或只有一个节点的情况),这些特殊情况应在程序开头加以判断。 - `mergeLists` 函数实现了交替合并的功能,确保最终结果满足题目要求。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值