哈希表
首先,哈希表一般利用map数据结构来实现,由于map是一个键值对存储的数据集,可以根据键名来获取对应的值。所以,利用这样的数据结构可以有效查找一个数组中元素的下标或者是元素的数量。一般我们可以把数组中的元素存储再map中的键名,再根据实际需求来设置键名对应的value值。
两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
var twoSum = function(nums, target) {
var mymap =new Map()
for(let i in nums){
var n = mymap.get(target-nums[i])
if(n!=null && n!=i){
return [n,i]
}
mymap.set(nums[i],i)
}
};
这里需要得到一个和为target的数,那么为了利用map的查询功能,我们可以将想要查找的数用target-nums[i]来表示(nums[i]是我们循环遍历的元素)。这样就可以对每个元素进行查找,直到找到map中符合条件的数。注意:这里map中的内容是每次遍历元素时都一个一个进入进map集合中的mymap.set(nums[i],i)
这类题目解法有以下几个关键点:
- 重循环遍历每个元素
- 根据题目给的条件在map中根据与当前元素相关的键名如
mymap.get(target-nums[i])进行查找 - 最后要记得将当前元素和相关键值插入map中
mymap.set(nums[i],i)
大餐计数
大餐 是指 恰好包含两道不同餐品 的一餐,其美味程度之和等于 2 的幂。
你可以搭配 任意 两道餐品做一顿大餐。
给你一个整数数组 deliciousness ,其中 deliciousness[i] 是第 i 道餐品的美味程度,返回你可以用数组中的餐品做出的不同 大餐 的数量。结果需要对 109 + 7 取余。
注意,只要餐品下标不同,就可以认为是不同的餐品,即便它们的美味程度相同。
var countPairs = function(deliciousness) {
const m = 1000000007;
let max=0;
for (let val of deliciousness) {
if(val>max){
max=val;
}
}
let num = 0;
let map = new Map();
for (let i = 0; i < deliciousness.length; i++) {
for (let sum = 1; sum <= max*2; sum*=2) {
const s = map.get(sum - deliciousness[i]) || 0
num = num + s
}
map.set(deliciousness[i], (map.get(deliciousness[i]) || 0) + 1);
}
return num%m;
};
根据题目意思,可以想到我们首先会用一个循环来遍历数组中的每一个元素,接着每一个元素都可能可以和其它元素相加凑成2的幂,所以很自然我们就可以想到用mymap.get(target-nums[i])来mymap进行查找,这里关键点再我们应该查找的value值是啥,上一题的value值设置的很明delic显是元素再数组中的下标。那么这道题根据题目意思(下标不同课认为是不同的餐品,而且最终需要得出不同组合的总数),可得我们需要将相同美味程度deliciousness[i]的餐品做一个统计,将每次遍历到的元素的值相同的做统计即在原有基础上加一map.set(deliciousness[i], (map.get(deliciousness[i]) || 0) + 1)。
ok,到这里我们已经基本完成了这类题的框架。于是再添加一些细节就OK了。细节呢就是对于遍历到的元素deliciousness[i]能与当前map集合中的多少个数字进行相加得到2的幂。这里我们可以对可能可以得到的2的幂进行一个遍历,遍历到max*2(意思是数组中最大的数的两倍,因为数组中任何数相加不可能比最大数的两倍还大)。于是我们就可以将mymap.get(target-nums[i])改成map.get(sum - deliciousness[i])来在map中查找符合条件的数字的数量啦,这里sum是可能可以得到的2的幂。
下面的题就练练手吧
和为 K 的子数组
给定一个整数数组和一个整数 K,你需要找到该数组中和为 K 的连续子数组的个数
function subarraySum(nums: number[], k: number): number {
const mp = new Map<number, number>();
mp.set(0, 1);
let count = 0,
pre = 0;
for (const x of nums) {
pre += x;
if (mp.has(pre - k)) count += mp.get(pre - k)!;
if (mp.has(pre)) mp.set(pre, mp.get(pre)! + 1);
else mp.set(pre, 1);
}
return count;
}
无重复字符串的最长子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
function lengthOfLongestSubstring(s: string): number {
const n = s.length;
let sub = "";
let res = "";
for (let i = 0; i < n; i++) {
if (!sub) {
sub += s[i];
if (i === n - 1 && res.length < sub.length) res = sub;
} else {
if (!sub.includes(s[i])) {
sub += s[i];
if (i === n - 1 && res.length < sub.length) res = sub;
} else {
if (sub.length > res.length) res = sub;
sub = sub.substr(sub.indexOf(s[i]) + 1) + s[i];
}
}
}
return res.length;
}