其實今天的題目還是挺簡單的,但心思不定,做半天才做出來……其實主要目的還是熟悉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;
}