文章目錄
Leetcode 面試題 10.01. 合併排序的數組
問題描述
給定兩個排序後的數組 A 和 B,其中 A 的末端有足夠的緩衝空間容納 B。 編寫一個方法,將 B 合併入 A 並排序。
初始化 A 和 B 的元素數量分別爲 m 和 n。
示例:
輸入:
A = [1,2,3,0,0,0], m = 3
B = [2,5,6], n = 3
輸出: [1,2,2,3,5,6]
說明:
A.length == n + m
解題報告
一般情況下,合併兩個有序數組時,還需要第三個數組,大小爲兩個有序數組的大小之和。但是此題數組 A
的大小足夠大,所以從兩個有序數組的末尾元素開始處理,從數組 A
的末尾開始填充。
時間複雜度:
空間複雜度:
實現代碼
class Solution {
public:
void merge(vector<int>& A, int m, vector<int>& B, int n) {
int i=m-1,j=n-1,pos=m+n-1;
while(j>=0&&i>=0){
if(A[i]>B[j]) A[pos--]=A[i--];
else A[pos--]=B[j--];
}
while(j >= 0) A[pos--] = B[j--];
}
};
Leetcode 面試題 02.02. 返回倒數第 k 個節點
問題描述
面試題 02.02. 返回倒數第 k 個節點
實現一種算法,找出單向鏈表中倒數第 k 個節點。返回該節點的值。
注意:本題相對原題稍作改動
示例:
輸入: 1->2->3->4->5 和 k = 2
輸出: 4
說明:
給定的 k 保證是有效的。
解題報告
設置兩個指針 slow
,fast
,fast
先走 k
步,然後 slow
,fast
以相同速度前進,當 fast
到達末尾時,slow
即在倒數第 k
個節點。這種邏輯和 Leetcode 面試題52.兩個鏈表的第一個公共節點【思路巧妙,源自題解區】 有點相似。
時間複雜度:
空間複雜度:
實現代碼
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
int kthToLast(ListNode* head, int k) {
ListNode* slow=head,*fast=head;
for(int i=1;i<=k;i++){
fast=fast->next;
}
while(fast){
slow=slow->next;
fast=fast->next;
}
return slow->val;
}
};
Leetcode 26. 刪除排序數組中的重複項
問題描述
給定一個排序數組,你需要在 原地 刪除重複出現的元素,使得每個元素只出現一次,返回移除後數組的新長度。
不要使用額外的數組空間,你必須在 原地 修改輸入數組 並在使用 O(1) 額外空間的條件下完成。
示例 1:
給定數組 nums = [1,1,2],
函數應該返回新的長度 2, 並且原數組 nums 的前兩個元素被修改爲 1, 2。
你不需要考慮數組中超出新長度後面的元素。
解題報告
設置兩個指針 i
,j
,i
指着當前有效的索引,j
則跳過重複元素,將非重複元素依次放到指針 i
所在的位置,然後 i
往後移。
時間複雜度:
空間複雜度:
需要注意的是索引的判斷,一不小心就容易越界。
實現代碼
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if(nums.size()==0) return 0;
int i=0,j=1;
while(j<nums.size()){
while(j<nums.size()&&nums[j]==nums[j-1])j++;
if(j<nums.size())
nums[++i]=nums[j++];
}
return i+1;
}
};
Leetcode Leetcode 27. 移除元素
問題描述
給你一個數組 nums 和一個值 val,你需要 原地 移除所有數值等於 val 的元素,並返回移除後數組的新長度。
不要使用額外的數組空間,你必須僅使用 O(1) 額外空間並 原地 修改輸入數組。
元素的順序可以改變。你不需要考慮數組中超出新長度後面的元素。
示例 1:
給定 nums = [3,2,2,3], val = 3,
函數應該返回新的長度 2, 並且 nums 中的前兩個元素均爲 2。
你不需要考慮數組中超出新長度後面的元素。
解題報告
和上一題有一點相似之處,設置指針 l
指向數組的頭部,設置指針 r
指向數組的尾部。將 r
指向非 val
的元素,然後將左邊的 val
移到右邊。
while(l<=r)
取等號的原因是:如果數組只有一個元素而且等於 val,會無法刪除該元素。
if(l<=r&&nums[l]==val)
中需要滿足 l<=r
的原因是從 while(l<=r&&nums[r]==val)
這個循環跳出來有可能是 l>r
且此時 r<0
。
時間複雜度:
空間複雜度:
實現代碼
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int clipLen=0,l=0,r=nums.size()-1;
while(l<=r){
while(l<=r&&nums[r]==val) {
r--;
clipLen++;
}
if(l<=r&&nums[l]==val){
nums[l]=nums[r--];
clipLen++;
}
l++;
}
return nums.size()-clipLen;
}
};
總結
指針在移動的時候,一定要注意一些邊界條件,很容易就發生越界錯誤了。
- 兩個指針的關係判斷時,是否取等號;
- 從循環中跳出時,要全面考慮跳出循環的條件。
參考資料
[1] Leetcode 面試題 10.01. 合併排序的數組
[2] Leetcode 面試題 02.02. 返回倒數第 k 個節點
[3] Leetcode 面試題52.兩個鏈表的第一個公共節點【思路巧妙,源自題解區】
[4] Leetcode 26. 刪除排序數組中的重複項
[5] Leetcode 27. 移除元素