版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
其实今天的题目还是挺简单的,但心思不定,做半天才做出来……其实主要目的还是熟悉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;
}