两数之和 C++实现(力扣题目1)

给定一个整数数组 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]
示例 3:

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

  • 思路一

看到这道题目的第一想法依然是暴力法,想要在数组中找到和为目标值target的那两个数,那我把整个数组都遍历一遍,两两相加,看它们的和是否为target,如果不是的话我再换两个数,如此进行下去,就一定会找到我们需要的数以及它们对应的下标。

 

暴力法的流程思想就是上面这样的,两两相加看它们的和是否等于target,但是我们可以仔细看一看,这样其实是有重复运算的,比如【第一轮的①和第二轮的①】运算结果是一样的,两者对最后我们要求解的结果的影响是一样的,无非返回结果是[0,1],[1,0]顺序不同而已。所以在实际编程时应该优化一下(在程序中优化方法就是 j=i+1)

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

这个程序应该比较容易理解,就不逐句给大家讲解了。 

  •  思路二

        利用哈希表。刚才上面我们使用的两层for循环遍历的方法可以解决这个问题,而且相信大家拿到这道题的第一想法都是思路一,但是呢这种方法用了两层for循环,所以时间复杂度比较高。为了简化时间复杂度就尝试转换一下思路,用哈希表。

        我们先看解题思路是怎样的

对应的程序如下: 

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> mm;           //key是元素值,val是下标
        for(int i=0;i<nums.size();i++)
        {
            int find=target-nums[i];
            if(mm.count(find)!=0)
            {
                vector<int> vec{i,mm[find]};  //mm[find] 是 如果存在该变量则直接返回对应value,
                                              //如果不存在则增加该key值并自动初始化为0(这时候一定是存在的)
                return vec;
            }                 
            //unordered_map<int,int>
            mm[nums[i]]=i;                    // map的初始化方法之 直接赋值
        }
        return {};
    }
};

下面对这个程序进行简单注释: 

unordered_map<int,int> mm;           //key是元素值,val是下标

这一句就是创建了一个容器mm,unordered_map类型,其中的key是int类型,value也是int类型 。可能大家对这一句话完全不理解,unordered_map类型是什么类型?它里面为什么可以同时存两种类型的元素?key是什么?value又是什么?一头雾水完全不懂,不要着急下面为大家逐一解答:

首先unordered_map类型是C++STL标准库中提供的一种存储数据的结构(或者叫容器),前缀unordered就是“无序地”意思。与它看起来有点像的还有(map、multimap、unordered_map,大家感兴趣的可以去查一下)

为了方便起见我们先看不带前缀的map,map是STL的一个关联容器,关联式容器依据特定的排序准则,自动为其元素排序。map的元素都是“实值/键值”所形成的一个队组(key/value pairs),每个元素有一个键,是排序准则的基础,每个键只能出现一次不能重复。

而加上前缀unordered后成为unordered_map,就表示把元素添加进去后,不会根据键值进行自动排序,其中的元素顺序就是你添加元素的顺序。

 for(int i=0;i<nums.size();i++)

这一句就是逐个遍历数组中的元素

int find=target-nums[i];

定义一个变量find,这个find的作用就是我们之前提到的 每当遍历到一个元素 i ,就去哈希表里查找有没有一个元素等于target – i  (注意表述与代码稍有不一)

if(mm.count(find)!=0)
            {
                vector<int> vec{i,mm[find]};  //mm[find] 是 如果存在该变量则直接返回对应value,
                                              //如果不存在则增加该key值并自动初始化为0(这时候一定是存在的)
                return vec;

count()是 C++中unordered_map的内置方法,用于通过给定 key 对unordered_map中存在的元素数量进行计数。如果count(find)不为0,就意味着在unordered_map中找到了我们需要的数字,此时返回vec{i,mm[find]}就可以了

mm[nums[i]]=i;                    // map的初始化方法之 直接赋值

这是unordered_map的一种初始化方法,当然也有其他初始化方法,这里不做详细介绍,请大家自行查询一下。

 到这里我们已经成功地利用两种方法解决这道题目了,但是我们应该思考一下:

  1. 为什么第二种方法(哈希表)的存取查找比较快?

        (方法一运行时长)

         (方法二运行时长)

 

 因为有种算法叫哈希算法,哈希算法会根据你要存入的数据,先通过该算法计算出一个地址值,这个地址值就是你需要存入到集合当中的数据的位置,而不会像数组那样一个个地进行挨个存储,挨个遍历一遍后面有空位就存这种情况。当你查找时,也是根据这个哈希算法来的,将你要查找的数据进行计算,得出一个地址,这个地址会映射到集合当中的位置,这样就能直接去这个位置找了,而不需要像数组那样,一个一个去遍历比对查找。这样自然就提高了速度。

(这么说可能大家还是不懂)再介绍一下,哈希算法有一个强大的功能,它使得我们通过查找关键字但不需要逐个比较的方法就可以获得需要的记录的存储位置。存储位置=y(关键字),这个y就是哈希算法。它使得每个关键字key对应一个存储位置,查找时根据这个确定的对应关系找到给定值key的映射y(key),若查找集合中存在这个记录,则必定在y(key)的位置上。

整个过程就两步:①在存储时,通过y函数计算一个地址,并按照这个地址存储该记录②当查找记录时,我们通过同样的y函数计算记录的地址,按此地址访问该记录。由于存取过程采用的是同一个y函数,因此结果当然也是相同的

猜你喜欢

转载自blog.csdn.net/yangSHU21/article/details/130813347