LeetCode143-重排链表

在这里插入图片描述

方法一:数组

class Solution {
public:
	void reorderList(ListNode* head) {
		map<int, ListNode*> m;
		int num = 0;
		while (head) {
			m[num] = head;
			num++;
			head = head->next;
		}
		num--;
		if (num < 2) return;
		int i = 0;
		while (i < num) {
			m[i]->next = m[num];
			i++;
			if (i == num) break;  // 链表长度为偶数时会提前相遇
			m[num]->next = m[i];
			num--;
		}
		m[i]->next = nullptr;
	}
};

方法二:递归

class Solution {
public:
    void reorderList(ListNode* head) {
        if (!head || !head->next || !head->next->next ) return;
        int len = 0;
        ListNode* h = head;
        // 求出节点数
        while (h) {
            len++;
            h = h->next;
        }
        reorderListHelper(head, len);
    }

private:
    ListNode* reorderListHelper(ListNode* head, int len) {
        if (len == 1) {
            ListNode* outTail = head->next;
            head->next = nullptr;
            return outTail;
        }
        if (len == 2) {
            ListNode* outTail = head->next->next;
            head->next->next = nullptr;
            return outTail;
        }
        // 得到对应的尾节点,并且将头结点和尾节点之间的链表通过递归处理
        ListNode* tail = reorderListHelper(head->next, len - 2);
        // 中间链表(已经处理好的中间部分,相当于最终链表的尾部)的头结点。(注:递归最先处理的是最终链表的尾部)
        ListNode* subHead = head->next;
        head->next = tail;
        ListNode* outTail = tail->next;  // 上一层 head 对应的 tail
        tail->next = subHead;
        return outTail;
    }
};

方法三:重排链表
步骤一,用快慢指针找链表中点,把链表分为前后俩部分
步骤二,翻转后半部链表,翻转前要把前后两部分分开
步骤三,合并两部分链表

class Solution {
public:
    void reorderList(ListNode* head) {
        if (!head || !head->next || !head->next->next) {
        	return;
        }
        //找中点,链表分成两个
        ListNode* slow = head;
        ListNode* fast = head->next;
        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
        }
		
		// 在反转之前需要的一个操作是将前后半部分断开
        ListNode* newHead = slow->next;
        slow->next = nullptr;

        //第二个后面部分链表翻转
        newHead = reverseList(newHead);

        //链表节点依次连接
        while (newHead) {
            ListNode* temp = newHead->next;
            newHead->next = head->next;
            head->next = newHead;
            head = newHead->next;
            newHead = temp;
        }

    }

private:
    ListNode* reverseList(ListNode* head) {
        if (!head) return nullptr;
        ListNode* tail = head;
        head = head->next;

        tail->next = nullptr;

        while (head) {
            ListNode* temp = head->next;
            head->next = tail;
            tail = head;
            head = temp;
        }

        return tail;
    }
};
class Solution {
publicvoid reorderList(ListNode head) {
    if (head == null || head.next == null) {
        return;
    }

    // 步骤 1: 通过快慢指针找到链表中点
    // 通过调节快慢指针的起始位置,可以保证前半部分的长度大于等于后半部分
    ListNode slow = head, fast = head.next;
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
    }

    // 步骤 2: 反转后半部分的链表
    // 在反转之前需要的一个操作是将前后半部分断开
    ListNode second = slow.next;
    slow.next = null;
    second = reverseList(second);

    // 步骤 3: 合并前半部分链表以及反转后的后半部分链表
    mergeList(head, second);
}

private ListNode reverseList(ListNode head) {
    ListNode prev = null, tmp = null, pointer = head;
    while (pointer != null) {
        tmp = pointer.next;
        pointer.next = prev;
        prev = pointer;
        pointer = tmp;
    }

    return prev;
}

privatevoid mergeList(ListNode first, ListNode second) {
    ListNode dummy = new ListNode(0);
    ListNode pointer = dummy;

    while (first != null && second != null) {
        pointer.next = first;
        first = first.next;
        pointer.next.next = second;
        second = second.next;
        pointer = pointer.next.next;
    }

    // 因为我们之前找中点的时候保证了前半部分的长度不小于后半部分的长度
    // 因此交叉后,多出来的部分只可能是前半部分,判断前半部分即可
    if (first != null) {
        pointer.next = first;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值