最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

【全球报资讯】【LeetCode哈希表#4】梦开始的地方:两数之和(map),以及关于容器map的一些代码技巧

来源:博客园

两数之和

力扣题目链接(opens new window)


(资料图片仅供参考)

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

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9

所以返回 [0, 1]

思路

暴力法

两层for循环,一个一个加起来然后判断呗

class Solution {public:    vector twoSum(vector& nums, int target) {        for(int i = 0; i < nums.size(); i++){            for(int j = i + 1; j < nums.size(); j++){                if(nums[i] + nums[j] == target){                    return {i, j};                }            }        }        //不满足条件返回空        return {};      }};
哈希法

没错,这个题也可以用哈希法去解

只不过这里我们使用的哈希结构有所不同,先分析一下解题思路

题目要求我们找到数组中两个数,这两个数加起来要等于输入的target值

假设,现在遍历到数组的第一个数 A

C = target - A;

那么如果数组中存在 C的话,我们就找到了两个符合条件的数{A, B},返回两者的下标即可

因此,我们需要有一个数据结构去存放已经遍历过的值和该值在数组中的下标

这是一个key-value的结构,对应到c++中可以通过map容器实现

C++中map,有三种类型:

映射底层实现是否有序数值是否可以重复能否更改数值查询效率增删效率
std::map红黑树key有序key不可重复key不可修改O(log n)O(log n)
std::multimap红黑树key有序key可重复key不可修改O(log n)O(log n)
std::unordered_map哈希表key无序key不可重复key不可修改O(1)O(1)

std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底层实现是红黑树。

因为本题并不需要key有序,所以使用unordered_map效率更高

那么key对应什么?value又对应什么呢?

我们想知道的是,某个值(当前遍历值与target作差之后的差值)是否被遍历过,即查找的对象是某个值,因此需要将遍历得到的数组元素值作为key,其下标作为value

流程

1、遍历数组,向unordered_map中查询当前遍历值对应的值是否被遍历过

2、如果查询到匹配值,返回该值对应的value,与当前遍历值的index组成一对结果

代码

主要障碍是对c++里面一些容器的操作不熟练(比如这里的map容器),这里直接粘的卡哥的代码

class Solution {public:    vector twoSum(vector& nums, int target) {        //声明一个unordered_map        std::unordered_map  map;        for(int i = 0; i < nums.size(); i++) {            // 遍历当前元素,并在map中寻找是否有匹配的key            // auto用于自动给迭代对象一个相应的数据类型            auto iter = map.find(target - nums[i]); //这里是定义了一个map的iterator吗?没见过这种写法            //end()指向的最后一个元素的后一个位置            //iter != map.end()是什么意思?其常被用于map容器遍历时的判断条件            //            if(iter != map.end()) { //找到了                /*                (*it).first会得到key,(*it).second会得到value。这等同于it->first和it->second*/                //{匹配值下标, 当前遍历值的下标}                return {iter->second, i};            }            // 如果没找到匹配对,就把访问过的元素和下标加入到map中            map.insert(pair(nums[i], i));         }        return {};    }};

后续需要对c++容器的使用做强化训练(专题:c++刷题常用容器简介,TBD)

关于iter != map.end()

这里需要从它的上一行代码开始说起

摘自《C++ Primer Plus第6版》:

C++11新增了一个工具,让编译器能够根据初始值的类型推断变量的类型。为此,它重新定义了auto的含义。auto是一个C语言关键字,但很少使用,有关其以前的含义,请参阅第9章。在初始化声明中,如果使用关键字auto,而不指定变量的类型,编译器将把变量的类型设置成与初始值相同:

那么auto iter = map.find(target - nums[i]);的含义是:

定义一个 迭代器iter用于在 map中寻找 target - nums[i]

如果 map.find(target - nums[i])等于 map.end(),那么键就没有找到

否则,find会返回一个指向找到的元素的迭代器

上述题解中的代码可写为:

std::unordered_map  map;unordered_map  ::iterator it = map.find(target - nums[i]);if (i != m.end()) { /* 找到了, 此时i->first就是匹配值下标(key), i->second是当前遍历值的下标(value) */}else {  /* 没找到f */ }

参考:https://stackoverflow.com/a/1939962/15272780

关键词: 数组元素 我们需要 数据类型