- 1. 两数之和
- 2. 删除排序数组中的重复项
- 3. 移除元素
- 4. 三数之和
- 5. 最接近的三数之和
- 6. 买卖股票的最佳时机 III
1. 两数之和
题目
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
知识点
- 哈希表
以空间换时间,将查找时间复杂度从O(n) 降低到 O(1),空间复杂度为O(n)
关键代码
unordered_map<int, int> umap;
auto j = umap.find(target - nums[i]);
if(j != umap.end() && j->second != i)
完整代码
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> res;
unordered_map<int, int> umap;
for(int i=0;i<nums.size();i++){
auto j = umap.find(target - nums[i]);
if(j != umap.end() && j->second != i){
res.push_back(j->second);
res.push_back(i);
break;
}
else
umap[nums[i]]=i;
}
return res;
}
};
2. 删除排序数组中的重复项
题目
给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。
你不需要考虑数组中超出新长度后面的元素。
知识点
- 双指针
慢指针作为结果数组的索引,快指针作为原始数组的索引。 - 注意判空
关键代码
if (nums.empty()) return 0;
完整代码
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if (nums.empty()) return 0;
int i=0;
for(int j=1;j<nums.size();j++){
if(nums[j]!=nums[i]){
i++;
nums[i]=nums[j];
}
}
return i+1;
}
};
3. 移除元素
题目
给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
你不需要考虑数组中超出新长度后面的元素
知识点
- 双指针改进:要删除的元素很少
例如,num=[1,2,3,5,4],Val=4。之前的算法会对前四个元素做不必要的复制操作。
另一个例子是 num=[4,1,2,3,5],Val=4。似乎没有必要将 [1,2,3,5],这几个元素左移一步,因为问题描述中提到元素的顺序可以更改。 - 思路
当我们遇到 nums[i] = valnums[i]=val 时,我们可以将当前元素与最后一个元素进行交换,并释放最后一个元素。这实际上使数组的大小减少了 1。
算法 | 时间 | 内存 |
---|---|---|
改进 | 0 ms | 11.2 MB |
双指针 | 4 ms | 11.1 MB |
时间复杂度:O(n),i 和 n 最多遍历 n 步。在这个方法中,赋值操作的次数等于要删除的元素的数量。
关键代码
if(nums[i]==val){
nums[i]=nums[n-1];
n--;
}
完整代码
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int i=0;
int n=nums.size();
while(i<n){
if(nums[i]==val){
nums[i]=nums[n-1];
n--;
}
else
i++;
}
return i;
}
};
4. 三数之和
题目
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
知识点
- 数组遍历
固定i,在i的右端选择L和R使得三数之和满足条件。 - 复杂度
时间:数组排序 O(nlogn),遍历数组 O(n),双指针遍历 O(n),总体O(nlogn)+O(n)∗O(n)=O(n2)
空间:O(1)
关键代码
if(sum==0){
vector<int> tmp{nums[i],nums[L],nums[R]};
res.push_back(tmp);
while(L<R && nums[L+1]==nums[L]) L++;
while(L<R && nums[R-1]==nums[R]) R--;
L++;
R--;
}
完整代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
if(nums.size()<3) return res;
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size();i++){
if(nums[i]>0) break;
if(i>0 && nums[i]==nums[i-1]) continue;//重复解
int L=i+1,R=nums.size()-1;
while(L<R){
int sum=nums[i]+nums[L]+nums[R];
if(sum==0){
vector<int> tmp{nums[i],nums[L],nums[R]};
res.push_back(tmp);
while(L<R && nums[L+1]==nums[L]) L++;
while(L<R && nums[R-1]==nums[R]) R--;
L++;
R--;
}
else if(sum>0) R--;
else L++;
}
}
return res;
}
};
5. 最接近的三数之和
题目
例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
知识点
- 数组遍历
与上题类似,但是本题没有可以提前结束的条件
关键代码
int sum=nums[i]+nums[L]+nums[R];
if(abs(sum-target)<abs(ans-target))
ans = sum;
if(sum==target){
return ans;
}
完整代码
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());
int ans = nums[0]+nums[1]+nums[2];
for(int i=0;i<nums.size();i++){
int L=i+1,R=nums.size()-1;
while(L<R){
int sum=nums[i]+nums[L]+nums[R];
if(abs(sum-target)<abs(ans-target))
ans = sum;
if(sum==target){
return ans;
}
else if(sum>target) R--;
else L++;
}
}
return ans;
}
};
6. 买卖股票的最佳时机 III
题目
输入: [3,3,5,0,0,3,1,4]
输出: 6
解释: 在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。
随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。
知识点
此题依然可以使用贪心思想求解。
因为题目要求最多不超过两次交易,因此可以价格序列正向贪心一次,反向贪心一次,然后取二者和的最大值即为答案。
关键代码
完整代码
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.size() == 0) return 0;
int st = prices[0];
vector<int> ans;
ans.push_back(0);
// 正向贪心,结果存储在 ans 中,注意此时范围是 1 ~ (size() - 2),计算的是 prices[now] - buy,st 是当前最优买入价
for(int i = 1; i < prices.size() - 1; i ++)
{
ans.push_back(max(prices[i] - st, ans[i - 1]));
st = min(prices[i], st);
}
st = prices[prices.size() - 1];
int outp = ans[prices.size() - 1];
// 反向贪心,结果存储在 ans 中,注意此时范围是 (size() - 2) ~ 1,计算的是 sell - prices[now],st 是当前最优卖出价
for(int i = prices.size() - 2; i > 0; i --)
{
outp = max(outp, st - prices[i] + ans[i]);
st = max(prices[i], st);
}
return outp;
}
};