合并链表和数组去重

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/HermitSun/article/details/102574257

其实今天的题目还是挺简单的,但心思不定,做半天才做出来……其实主要目的还是熟悉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;
}

猜你喜欢

转载自blog.csdn.net/HermitSun/article/details/102574257