Leetcode刻意练习1——数组

  • 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 ms11.2 MB
双指针4 ms11.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;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值