86. Partition List(分隔链表)

2018-12-04  本文已影响17人  Aiewing

题目

LeetCode中文站

解答

大致解析题目意思,就是把一个链表分成两个部分,但是相对位置不变化,第一想法就是直接遍历一次,分别使用两个新链表存起来,最后拼接在一起,就是需要的最后答案了。

class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
        // 左边链表头
        ListNode *leftHeadNode = new ListNode(0);
        // 右边链表头
        ListNode *rightHeadNode = new ListNode(0);
        // 左边链表的当前位置
        ListNode *leftCurrentNode = leftHeadNode;
        // 右边链表的当前位置
        ListNode *rightCurrentNode = rightHeadNode;
        while (head != NULL) {
            if (head->val < x) {
                // 把小于x的节点放到左链表最后 并移动当前节点到下个节点
                leftCurrentNode->next = head;
                leftCurrentNode = leftCurrentNode->next;
            } else {
                // 把大于等于x的节点放到右链表最后 并移动当前节点到下个节点
                rightCurrentNode->next = head;
                rightCurrentNode = rightCurrentNode->next;
            }
            head = head->next;
        }
        // 拼接两个列表
        leftCurrentNode->next = rightHeadNode->next;
        rightCurrentNode->next = NULL;
        return leftHeadNode->next;
    }
};

以上代码时间复杂度为O(n),创建了两个新的链表,空间复杂度为O(n)

以上代码时间复杂度已经很低了,但是空间复杂度还有一定的优化的空间,之前我们创建了两个链表,现在考虑能不能就在原来的链表上操作,不创建新的链表呢?
这个我还没想出来,但是我们可以创建一个链表,让另外一部分在原来的链表上操作,最后拼接起来。

class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
        // 左边链表头
        ListNode *leftHeadNode = new ListNode(0);
        // 原节点的父节点
        ListNode *fatherHeadNode = new ListNode(0);
        // 为了让第一个节点拥有父节点 删除节点的时候容易一点 所以为原链表设置一个父节点
        fatherHeadNode->next = head;
        // 左边链表的当前位置
        ListNode *leftCurrentNode = leftHeadNode;
        // 原链表的当前位置
        ListNode *headCurrentNode = fatherHeadNode;
        while (headCurrentNode->next != NULL) {
            // 判断当前的值
            if (headCurrentNode->next->val < x) {
                // 把小于x的节点放到左链表最后 并移动当前节点到下个节点
                leftCurrentNode->next = headCurrentNode->next;
                leftCurrentNode = leftCurrentNode->next;
                // 删除当前的节点
                headCurrentNode->next = headCurrentNode->next->next;
                leftCurrentNode->next = NULL;
            } else {
                // 当前节点不变 移动当前节点到下个节点
                headCurrentNode = headCurrentNode->next;
            }
        }
        // 拼接两个列表
        leftCurrentNode->next = fatherHeadNode->next;
        return leftHeadNode->next;
    }
};

以上代码时间复杂度为O(n),但是只创建了一个新的链表,虽然空间复杂度还是为O(n),但是在使用的空间上比之前的算法减少了一点。

在朋友的提示下,终于想到了时间复杂度O(1)的解法,说起来也简单,之前怎么就没有想到呢?

class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
        // 左边链表头
        ListNode *leftHeadNode = new ListNode(0);
        // 右边链表头
        ListNode *rightHeadNode = new ListNode(0);
        rightHeadNode->next = head;
        // 左边链表的当前位置
        ListNode *leftCurrentNode = leftHeadNode;
        // 右边链表的当前位置
        ListNode *rightCurrentNode = rightHeadNode;
        while (rightCurrentNode->next != NULL) {
            if (rightCurrentNode->next->val < x) {
                // 移除这个点 并重新拼接原来的节点
                leftCurrentNode->next = rightCurrentNode->next;
                leftCurrentNode = leftCurrentNode->next;
                rightCurrentNode->next = rightCurrentNode->next->next;
            } else {
                rightCurrentNode = rightCurrentNode->next;
            }
        }
        leftCurrentNode->next = rightHeadNode->next;
        return leftHeadNode->next;
    }
};

以上代码时间复杂度为O(n),空间复杂度还是为O(1)

上一篇下一篇

猜你喜欢

热点阅读