文章目录
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
的末尾开始填充。
时间复杂度:
O
(
m
+
n
)
O(m+n)
O(m+n)
空间复杂度:
O
(
1
)
O(1)
O(1)
实现代码
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.两个链表的第一个公共节点【思路巧妙,源自题解区】 有点相似。
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
实现代码
/**
* 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
往后移。
时间复杂度:
O
(
m
)
O(m)
O(m)
空间复杂度:
O
(
1
)
O(1)
O(1)
需要注意的是索引的判断,一不小心就容易越界。
实现代码
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
。
时间复杂度:
O
(
m
)
O(m)
O(m)
空间复杂度:
O
(
1
)
O(1)
O(1)
实现代码
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. 移除元素