143. Reorder List

本文介绍了解决链表问题的关键技巧,包括使用快慢指针找到链表中点、单链表翻转及两个链表的合并。通过示例代码详细解释了每种方法的实现过程。

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

关于链表问题,个人总结了几个考点,可以作为解题思路,今后也会补充。

1. 找到链表的中点,可以使用快慢指针。

2. 单链表翻转。

3. 两个链表合并。

-----------------------------------单链表中点-----------------------------------------------------------------------------------------------------------------

如何在单链表中找到链表的中点,最暴力的方法是遍历链表,求得链表的长度,在遍历链表的一半找到中点,但是如果遇到特别长的链表,这个效率太差,所以我们可以使用“快慢指针”的方法来解决。

上例子:求0 --> 1 --> 2 --> 3 -->4 -->5 --> NULL 的中点。

设置slow,fast指针,slow指向head,fast指向head->next,快指针一次走两步,慢指针一次走一步,当快指针走到最后的时候,慢指针就是中点啦。

代码如下:

/**
 * Definition of ListNode
 * class ListNode {
 * public:
 *     int val;
 *     ListNode *next;
 *     ListNode(int val) {
 *         this->val = val;
 *         this->next = NULL;
 *     }
 * }
 */
class Solution {
public:
    /**
     * @param head: The first node of linked list.
     * @return: You should return the head of the sorted linked list,
                    using constant space complexity.
     */
    ListNode *sortList(ListNode *head) {
        // write your code here
        if (head == NULL || head->next == NULL) {
            return head;
        }
        ListNode *slow, *fast;
        slow = head;
        fast = head;
        while (fast->next != NULL && fast->next->next != NULL) {
            slow = slow->next;
            fast = fast->next->next;
        }
        ListNode *mid = slow->next;
        slow->next = NULL;
        
        ListNode *l1 = sortList(head);
        ListNode *l2 = sortList(mid);
        ListNode *sorted = mergeList(l1, l2);
        return sorted;
    }
    ListNode* mergeList(ListNode *list1, ListNode *list2) {
        if (list1 == NULL) {
            return list2;
        }
        if (list2 == NULL) {
            return list1;
        }
        ListNode *dummy = new ListNode(-1);
        ListNode *temp = dummy;
        while (list1 != NULL && list2 != NULL) {
            if (list1->val < list2->val) {
                temp->next = list1;
                list1 = list1->next;
            } else {
                temp->next = list2;
                list2 = list2->next;
            }
            temp = temp->next;
        }
        if (list1 != NULL) {
            temp->next = list1;
        }
        if (list2 != NULL) {
            temp->next = list2;
        }
        return dummy->next;
    }
};
-----------------------------------单链表翻转-----------------------------------------------------------------------------------------------------------------

翻转链表,这个就不细说了,需要三个指针分别指向前一个节点,当前节点,后一个节点

依然是代码:

ListNode *reverseList(ListNode *head) {
        if (head == NULL || head->next == NULL) {
            return head;
        }
        ListNode *pre, *cur;
        pre = head;
        cur = head->next;
        head->next = NULL;
        while (cur != NULL) {
            ListNode *temp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = temp;
            
        }
        return pre;
    }
------------------------------------------------------------------------------------------------------------------------------------------------------------------

来一个例子说明吧:

Given a singly linked list LL0L1→…→Ln-1Ln,
reorder it to: L0LnL1Ln-1L2Ln-2→…

You must do this in-place without altering the nodes' values.

For example,
Given {1,2,3,4}, reorder it to {1,4,2,3}.


我们试一个比较长的链表,为了容易理解,节点中的数字代表节点的位置,并不是说这个链表的有序链表,因为这样比较直观:

0 --> 1--> 2--> 3--> 4--> 5--> 6--> 7--> 8--> 9--> NULL

排序后应该是这样的:

0 --> 9--> 1--> 8--> 2--> 7--> 3--> 6--> 4--> 5--> NULL

排序后的链表特点是,奇数位置的节点正序(位置),偶数位置的节点是逆序(位置),由此可以想见,就是要把链表分成两部分,对后一部分进行翻转,然后再把两个链表归并起来。对于归并,根据要求不同会略有不同,但是万变不离其宗,但是要注意链表的“来龙去脉”。

把代码贴上来吧,自己写的,可能有点挫。。。。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    void reorderList(ListNode* head) {
        if (head == NULL || head->next == NULL) {
            return;
        }
        ListNode *fast = head, *slow = head;
        while (fast->next != NULL && fast->next->next != NULL) {
            fast = fast->next->next;
            slow = slow->next;
        }
        fast = slow->next;
        slow->next = NULL;
        slow = head;
        fast = reverseList(fast);
        ListNode* dummy = new ListNode(0);
        ListNode* temp = dummy;
        while (slow != NULL && fast != NULL) {
            temp->next = slow;
            temp = temp->next;
            slow = slow->next;
            temp->next = fast;
            temp = temp->next;
            fast = fast->next;
        }
        if (slow != NULL) temp->next = slow;
        if (fast != NULL) temp->next = fast;
        head = dummy->next;
    }
    ListNode* reverseList(ListNode* head) {
        if (head == NULL || head->next == NULL) {
            return head;
        }
        ListNode* pre = head;
        ListNode* cur = head->next;
        ListNode* temp = head;
        head->next = NULL;
        while (cur != NULL) {
            temp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = temp;
        }
        head = pre;
        return head;
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值