合併鏈表和數組去重

其實今天的題目還是挺簡單的,但心思不定,做半天才做出來……其實主要目的還是熟悉C++的語法,對象指針和動態分配內存的new運算符的處理還是不太熟悉。

合併鏈表的算法本身其實沒什麼可說的,只是感覺上對於鏈表的處理,通常情況下加個虛擬的頭結點能好很多。而且鏈表的一個很重要的特點是通過鏈接來連接,利用這一點可以減少不必要的空間開銷。比如合併鏈表,就不需要那些不必要的複製操作,直接改變每個結點鏈接的指向就行:

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
    ListNode *prehead = new ListNode(-1);
    ListNode *prev = prehead;
    while (l1 && l2)
    {
        if (l1->val <= l2->val)
        {
            prev->next = l1;
            l1 = l1->next;
        }
        else
        {
            prev->next = l2;
            l2 = l2->next;
        }
        prev = prev->next;
    }
    prev->next = l1 ? l1 : l2;
    return prehead->next;
}

數組去重本身並不是一件很麻煩的事,但是麻煩的是要在原來的數組上直接修改。身爲一個JS玩家,我第一反應當然是一行代碼完事:

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    return [...new Set(nums)].length;
};

但是對象解構語法並不會修改原來的數據,所以這段代碼是不符合要求的。用JS偷雞失敗之後,想了想,打算用set(和相同的思路)來解決這個問題:

/**
 * ------result------
 * memory: 11.5 MB (50%)
 * speed:  36 ms   (5%)
*/
int removeDuplicates(vector<int>& nums) {
    set<int> set(nums.begin(), nums.end());
    nums.assign(set.begin(), set.end());
    return nums.size();
}

過倒是過了,但是性能實在太差,而且佔用了額外空間。仔細讀題之後發現,題目說測試是以這種方式進行的:

for (int i = 0; i < len; i++) {
    print(nums[i]);
}

也就是說,其實只需要調整數組前n個元素就行(n爲數組中不重複的元素個數),n往後的元素改不改都無所謂。所以,只要把不重複的元素移到前面就好了;用兩個指針,一個表示需要移動的位置,一個表示現在的位置。之前用過類似的方法,但並不知道叫什麼,現在才知道叫雙指針法:

int removeDuplicates(vector<int>& nums) {
    int length = nums.size();
    if (length == 0 || length == 1)
    {
        return 0;
    }
    int i = 0;
    for (auto j = 1; j < length; ++j)
    {
        if (nums[j] != nums[i])
        {
            ++i;
            nums[i] = nums[j];
        }
    }
    return i + 1;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章