[LeetCode] Daily Practice 1 两数之和(Two Sum)

原文链接

题目来源:
力扣(LeetCode)

题目描述 📑

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 📝

示例1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1].

示例2:

输入: nums = [3,2,4], target = 6
输出: [1,2]

示例2:

输入:nums = [3,3], target = 6
输出:[0,1]

解题思路 🤔

思路一 暴力解法–遍历

那道题先用最简单直接的方式遍历解一下.

先审下题目,即有一个数组,需要从中取出两个数,然后返回两个数的下标.

最直接能想到的方式就是两层嵌套循环,分别取两个数,相加后判断是否等于target,等于则返回两数下标即可.

很简单直接,无需多做解释.

但是他的时间复杂度比较高为: O(n^2)

思路一 Code

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int size=nums.size();
        for(int fir_idx=0;fir_idx<size-1;++fir_idx){
            for(int sec_idx=fir_idx+1;sec_idx<size;++sec_idx){
                if(nums[fir_idx]+nums[sec_idx]==target){
                    return {fir_idx,sec_idx};
                }
            }
        }
        return {};
    }
};

思路一 提交结果

提交3次结果如下

提交结果执行用时内存消耗用时击败内存击败
通过260 ms9.9MB39.97%74.95%
通过276 ms9.9MB33%87%
通过352 ms9.8MB15%98%

思路二 LUT

暴力解完后,咱们来换一换思路,来看一下有没有可能把时间复杂度降低下来呢

再来审题,首先,我们先取一个值fir_val ,取值过程是一个遍历的过程,此时下标也是知道到,假设为fir_idx.

此时我们有了第一个值,第二个值要如何取得呢?OK 让我们再审下题:

题目需要我们找到两个值,满足:

fir_val+sec_val=target.

做一下简单的变化:

sec_val=target-fir_val.

💡OK!!!前面我们已经有了 fir_val,经过一个简单的减法,满足题目条件的第二个值是多少也就确定了.

伪代码如下:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
	    ...
        int size=nums.size();
        int sec_val=0;
        int sec_idx=0;
        for(int fir_val : nums){
	        sec_val=target-nums[fir_idx];
	        if(false==nums_has_sec_val()){
		        continue;
	        }
			sec_idx=get_val_idx();
			if(sec_idx==fir_idx){
				//因为题目不允许输出相同下标
			    continue;
			}
			return {fir_idx,sec_idx};
	    }
		return {};
    }
};

接下来,只要确定下,题目输入的数组中是否含有sec_val这个数值,并获取到这个sec_idx;

现在问题转换成了:如何确定,输入中含有sec_val,且获取到下标sec_idx;

查询某个key(即sec_val)的对应value(即sec_idx),这不就是查表么!

问题就变成了了,生成一张val-idx的表,即LUT,然后通过LUT确认输入是否含有sec_val,并查到sec_idx.

伪代码如下:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
	    ...
	    gen_LUT();
        int size=nums.size();
        int sec_val=0;
        int sec_idx=0;
        for(int fir_val : nums){
	        sec_val=target-nums[fir_idx];
	        if(LUT(sec_val,sec_idx).unfinded){
			    continue;
	        }
			if(sec_idx==fir_idx){
				//因为题目不允许输出相同下标
			    continue;
			}
			return {fir_idx,sec_idx};
	    }
		return {};
    }
};

如何实现LUT?,遍历一遍输入的数组,把val:index 插入到一个 map中就可以了;

在这个思路里,分别需要进行两个循环,这两个循环最大循环次数都小于 n(输入数组的大小),并且两次循环并不嵌套,故最坏情况下,需要进行的循环次数小于2n.

故时间复杂度为:O(2n)

思路二 Code

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int size=nums.size();
        std::map<int,int> lut;//value:index
        for(int idx=0;idx<size;++idx){
	        lut[nums[idx]]=idx;
        }        
        int sec_val=0;
        for(int fir_idx=0;fir_idx<size;++fir_idx){
	        sec_val=target-nums[fir_idx];
	        if(lut.find(sec_val)!=lut.end()&&lut[sec_val]!=fir_idx){
				return {fir_idx,lut[sec_val]};
	        }
	    }
		return {};
    }
};

思路二 提交结果

提交3次结果如下

提交结果执行用时内存消耗用时击败内存击败
通过12 ms12.3MB67.95%5.04%
通过8 ms12.2MB91.26%5.04%
通过16 ms12.2MB51.11%5.04%

可以看到用时上的提升特别大,从260ms以上降低到了 10ms左右,当然代价就是内存消耗增加了,原因在于额外维护了一个Map类型的LUT导致了空间消耗的增加,典型的拿空间换时间!

原文链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值