LeetCode:两数之和

题目:
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例:

给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

解题:
若将不能重复利用数组中同样的元素理解为每个元素只能遍历一次,那这道题将无法做了。
这里要理解为不能让同一样元素重复相加得到目标值。
举例:
num =[ 2 ,5, 5,8,9],target = 10;

若是遍历时下标控制错误,则会出现下标索引为1的元素5重复相加得到答案。 这样是错误的。

我在第一次编写时正是写错了for循环的起始值而出现了该错误。

 vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> tmp;
        int iSize=nums.size();
        for(int i=0;i<iSize-1;i++)
        {
             for(int j=1;j<iSize;j++)  //此处 int j=1是错的,这样随着i增加,每次都从num[1]加起。重复累加造成错误
             {
                 if((nums[i]+nums[j])==target)
                 {
                     tmp.push_back(i);
                     tmp.push_back(j);
                     break;  
                 }
             }    
        } 
        return tmp;
    }

正确修改代码为:

    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> tmp;
        int iSize=nums.size();
        for(int i=0;i<iSize-1;i++)
        {
             for(int j=i+1;j<iSize;j++) //j=i+1;
             {
                 if((nums[i]+nums[j])==target)
                 {
                     tmp.push_back(i);
                     tmp.push_back(j);
                     break;
                 }
             }            
        } 
        return tmp;

这里就是简单粗暴地利用嵌套for循环寻找符合条件的值,找到后将相应的下标值压入vector容器,break 跳出循环。
for循环为梯度变化, 复杂度为 n*(n-1)/2 , 为n的平方。

此处我有一个忽略的问题**,break只能跳出一级for循环**,实际上代码还会继续执行完剩下的循环。 所以还需要改进,加个标志位,跳出两级for循环。
而且在外层是要加在底部,而不能加在一进入。(因为会多进入一次进行判断

vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> tmp;
        int iSize=nums.size();
        bool flag =false;
        for(int i=0;i<iSize-1;i++)
        {
             for(int j=i+1;j<iSize;j++)
             {
                 if((nums[i]+nums[j])==target)
                 {
                     tmp.push_back(i);
                     tmp.push_back(j);
                     flag = true;
                     break;
                 }
             }
            if(flag)
            {
                break;
            }
        } 
        return tmp;
    }

此例还可以用来巩固vector容器的使用

    vector<int> tmp;
    tmp.push_back(i);
    int iSize=nums.size();

	for(vector<int>::iterator it=vecInt.begin(); it!=vecInt.end(); ++it)
	{
	      int iItem = *it; 
	      cout << iItem;    //或直接使用  cout << *it;
	}   //使用迭代器进行遍历
	tmp.pop_back(); //从尾部弹出 

本代码时间复杂度还是高,可以参考别人思路继续改进

1.就本段代码,还有改进之处
将return tmp放入内层条件为真的if 语句中 .省去了break
其次是在最外层加上没找到的语句提示及异常抛出

暴力法时间复杂度高。
这题很多题解是采用哈希表
主要是因为哈希表查找效率高,最好情况下为常数。
不过哈希表是不稳定的,在具体应用中还需要衡量。

看到哈希表,就顺带去看了哈希表的基本概念
c++中的map,hashmap等 。做个基本了解。
先附几个相关链接留作拓展
https://blog.csdn.net/city_to_sky/article/details/80042586
https://www.cnblogs.com/inception6-lxc/p/9263964.html

这道题有两遍哈希表和一遍哈希表解法。个人觉得一遍哈希表查找法更好。
两遍哈希表查找中,先要遍历一遍数组建立哈希表,第二遍遍历时查找符合条件的值,返回两个下标索引。
这个过程中,第一遍建表时可能会有两个键值相同的情况。出现冲突的情况 。 (这里需要有个哈希表有个处理了)
如果以c++标准库中map的思路来考虑,两个键值一样插入返回值会为false,即其中一个值会被丢弃。 这样当目标值正好是这两数之和时就不能找到答案。

一遍哈希表,边存边查找。 先查找后存。
这样, 如果前面没有符合条件的,并且前面已经出现重复值,那么这个值存入时被舍弃也没关系。 因为前面的相同值可以与其它值组成符合条件的解。
如果目标值正好是这俩重复值之和。 那么找到的是前一个相同值,返回该值和当前值的索引。 也是正确解。

一遍哈希表的代码

class Solution {
public:  
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> res;
        unordered_map<int, int> hash;//由于unorder_map的实现机理是hash_map,查的快  
        for(int i=0; i < nums.size();++i){
            int another = target - nums[i];
            if(hash.count(another)){  
                res = vector<int>({hash[another], i});
                return res;
            }
            hash[nums[i]] = i;
        }
        return res;
    }
};

每次遍历都看下表中是否已经存入了目标值-当前值,如果存在,则找到。如不存在,则将当前值也存入表中。

c++中unordered_map

以下内容系转载
——————————————————————————
unordered_map和map类似,都是存储的key-value的值,可以通过key快速索引到value。不同的是unordered_map不会根据key的大小进行排序,

存储时是根据key的hash值判断元素是否相同,即unordered_map内部元素是无序的,而map中的元素是按照二叉搜索树存储,进行中序遍历会得到有序遍历。

所以使用时map的key需要定义operator<。而unordered_map需要定义hash_value函数并且重载operator==。但是很多系统内置的数据类型都自带这些,

那么如果是自定义类型,那么就需要自己重载operator<或者hash_value()了。

结论:如果需要内部元素自动排序,使用map,不需要排序使用unordered_map

非频繁的查询用map比较稳定;频繁的查询用hash_map效率会高一些,c++11中的unordered_map查询效率会更高一些但是内存占用比hash_map稍微大点。unordered_map 就是 boost 里面的 hash_map 实现。

其实,stl::map对于与java中的TreeMap,而boost::unordered_map对应于java中的HashMap。
python中的map就是hashmap实现的,所以查询效率会比C++的map查询快。(java,python官方版的虚拟机都是用C语言实现的,所以内部的思想和方法都是通用的。)

若考虑有序,查询速度稳定,容器元素量少于1000,非频繁查询那么考虑使用map。
若非常高频查询(100个元素以上,unordered_map都会比map快),内部元素可非有序,数据大超过1k甚至几十万上百万时候就要考虑使用unordered_map(元素上千万上亿时4GB的内存就要担心内存不足了,需要数据库存储过程挪动到磁盘中)。
hash_map相比unordered_map就是千万级别以上内存占用少15MB,上亿时候内存占用少300MB,百万以下都是unordered_map占用内存少,
且unordered_map插入删除相比hash_map都快一倍,查找效率相比hash_map差不多,或者只快了一点约1/50到1/100。
综合非有序或者要求稳定用map,都应该使用unordered_map,set类型也是类似的。
unordered_map 查找效率快五倍,插入更快,节省一定内存。如果没有必要排序的话,尽量使用 hash_map(unordered_map 就是 boost 里面的 hash_map 实现)。
特性:
关联性:通过key去检索value,而不是通过绝对地址(和顺序容器不同)
无序性:使用hash表存储,内部无序
Map : 每个值对应一个键值
键唯一性:不存在两个元素的键一样
动态内存管理:使用内存管理模型来动态管理所需要的内存空间
unordered_map与map的区别
boost::unordered_map, 它与 stl::map的区别就是,stl::map是按照operator<比较判断元素是否相同,以及比较元素的大小,然后选择合适的位置插入到树中。所以,如果对map进行遍历(中序遍历)的话,输出的结果是有序的。顺序就是按照operator< 定义的大小排序。
而boost::unordered_map是计算元素的Hash值,根据Hash值判断元素是否相同。所以,对unordered_map进行遍历,结果是无序的。
用法的区别就是,stl::map 的key需要定义operator< 。 而boost::unordered_map需要定义hash_value函数并且重载operator==。对于内置类型,如string,这些都不用操心。对于自定义的类型做key,就需要自己重载operator< 或者hash_value()了。 map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的

最后,当不需要结果排好序时,最好用unordered_map。

1.原理
unordered_map: unordered_map内部实现了一个哈希表,因此其元素的排列顺序是杂乱的,无序的
2.使用
a.查找元素是否存在unordered_map<int, int> map中是否存在x:
map.find(x)!=map.end()或
map.count(x)!=0
b.插入数据
map.insert(Map::value_type(1,”Raoul”));
c.遍历
unordered_map<key,T>::iterator it;
(*it).first; //the key value
(*it).second //the mapped value
for(unordered_map<key,T>::iterator iter=mp.begin();iter!=mp.end();iter++)
{ cout<<”key value is”<first;
cout<<” the mapped value is “<< iter->second;}
3.评价
优点:
因为内部实现了哈希表,因此其查找速度非常的快
缺点:
哈希表的建立比较耗费时间
适用处:
对于查找问题,unordered_map会更加高效一些,因此遇到查找问题,常会考虑一下用unordered_map
https://blog.csdn.net/qiuyumin430/article/details/79486310
————————————_——————————
转载分割线

查找元素是否存在unordered_map<int, int> map中是否存在x:

map.find(x)!=map.end()或
map.count(x)!=0

hash[nums[i]] = i;
这个语句是索引也是插入,当表中没有该值时,该语句为插入。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值