本日 LeetCode 题目在次条,头条文章讲述 JavaScript 浮点数加减乘除的问题,并在文中给出优化建议及在工作中的使用方式。
不折腾的前端,和咸鱼有什么区别
目录 |
---|
一 目录 |
二 前言 |
三 解题及测试 |
四 LeetCode Submit |
五 解题思路 |
难度:简单
涉及知识:哈希表
题目地址:https://leetcode-cn.com/problems/minimum-index-sum-of-two-lists/
题目内容:
假设 Andy 和 Doris 想在晚餐时选择一家餐厅,
并且他们都有一个表示最喜爱餐厅的列表,
每个餐厅的名字用字符串表示。
你需要帮助他们用最少的索引和找出他们共同喜爱的餐厅。
如果答案不止一个,
则输出所有答案并且不考虑顺序。
你可以假设总是存在一个答案。
示例 1:
输入:
["Shogun", "Tapioca Express", "Burger King", "KFC"]
["Piatti", "The Grill at Torrey Pines",
"Hungry Hunter Steakhouse", "Shogun"]
输出: ["Shogun"]
解释: 他们唯一共同喜爱的餐厅是“Shogun”。
示例 2:
输入:
["Shogun", "Tapioca Express", "Burger King", "KFC"]
["KFC", "Shogun", "Burger King"]
输出: ["Shogun"]
解释:
他们共同喜爱且具有最小索引和的餐厅是“Shogun”,
它有最小的索引和1(0+1)。
提示:
两个列表的长度范围都在 [1, 1000]内。
两个列表中的字符串的长度将在[1,30]的范围内。
下标从0开始,到列表的长度减1。
两个列表都没有重复的元素。
小伙伴可以先自己在本地尝试解题,再回来看看 jsliang 的解题思路。
LeetCode 给定函数体:
/**
* @param {string[]} list1
* @param {string[]} list2
* @return {string[]}
*/
var findRestaurant = function(list1, list2) {
};
根据上面的已知函数,尝试破解本题吧~
确定了自己的答案再看下面代码哈~
index.js
/**
* @name 两个列表的最小索引总和
* @param {string[]} list1
* @param {string[]} list2
* @return {string[]}
*/
const findRestaurant = (list1, list2) => {
const map = new Map();
let result = [];
let min = 2000; // 数组范围在 [1, 1000]
for (let i = 0; i < list1.length; i++) {
map.set(list1[i], i);
}
for (let j = 0; j < list2.length; j++) {
const mark = map.get(list2[j]);
if (mark !== undefined) {
if (mark + j === min) {
result.push(list2[j]);
} else if (mark + j < min) {
result = [list2[j]];
min = mark + j;
} else {
break;
}
}
}
return result;
};
// const list1 = ['Shogun', 'Tapioca Express', 'Burger King', 'KFC'];
// const list2 = ['Piatti', 'The Grill at Torrey Pines', 'Hungry Hunter Steakhouse', 'Shogun'];
// ['Shogun']
const list1 = ['Shogun', 'Tapioca Express', 'Burger King', 'KFC'];
const list2 = ['KFC', 'Shogun', 'Burger King'];
// ['Shogun']
console.log(findRestaurant(list1, list2));
node index.js
返回:
['Shogun']
Accepted
* 133/133 cases passed (104 ms)
* Your runtime beats 97.54 % of javascript submissions
* Your memory usage beats 46.88 % of javascript submissions (43.2 MB)
首先,拿到题目,心里想到的,有两种破解思路,咱一个一个试试:
解法一
const findRestaurant = (list1, list2) => {
let result = [];
let min = Number.MAX_SAFE_INTEGER;
for (let i = 0; i < list1.length; i++) {
const index = list2.findIndex(item => item === list1[i]);
if (index > -1 && i + index === min) {
result.push(list1[i]);
}
if (index > -1 && i + index < min) {
result = [];
result.push(list1[i]);
min = i + index;
}
}
return result;
};
这个方法的思路比较清晰:
定义 result
接收结果。
定义 min
接收目前最少索引。
遍历 list1
,然后再遍历 list2
查找是否存在元素和 list[i]
相等(list2.findIndex()
相当于遍历了 list2
)。
如果找到了两个数组相同的元素,此时需要判断两种情况。
其一是 i + index === min
,说明存在多个相同最小索引的元素,此时 result
需要添加多一个元素。
其二是 i + index < min
,说明这次的索引比目前的最小索引还小,那就清空数组并添加当前元素,同时重新设置 min
。
最后将 result
返回出去。
Submit 提交结果:
Accepted
* 133/133 cases passed (144 ms)
* Your runtime beats 39.34 % of javascript submissions
* Your memory usage beats 53.13 % of javascript submissions (43 MB)
那么,挑刺:
使用了双重遍历:for
+ findIndex
。
没有设置中断条件,例如一开始 min
已经是 3,后面 i + index > 3
了,就不需要继续遍历了。
下面试试第二种方法:
解法二
const findRestaurant = (list1, list2) => {
const map = new Map();
let result = [];
let min = 2000; // 数组范围在 [1, 1000]
for (let i = 0; i < list1.length; i++) {
map.set(list1[i], i);
}
for (let j = 0; j < list2.length; j++) {
const mark = map.get(list2[j]);
if (mark !== undefined) {
if (mark + j === min) {
result.push(list2[j]);
} else if (mark + j < min) {
result = [list2[j]];
min = mark + j;
} else {
break;
}
}
}
return result;
};
在这个方法中,我们添加了一个哈希表,并进行了两次遍历:
遍历 list1
,将其所有元素添加进 Map
哈希表中。
遍历 list2
,查找 Map
中是否存在 list2[j]
。
如果查找的 list2[j]
存在于哈希表中,表明这个元素是存在的,进入 if
内部。
判断 查找到的索引 + 当前索引 是否等于当前最小值。如果是,则给 result
添加当前元素,表明当前最小值不止有一个。
判断 查找到的索引 + 当前索引 是否小于当前最小值。如果是,证明需要重新设置 result
,即 result = [list2[j]]
。
判断 查找到的索引 + 当前索引 是否超过最小值,如果超过,中断循环。
重复步骤 3 - 6,得到所有结果,最后通过 result
返回出去。
Submit 提交:
Accepted
* 133/133 cases passed (104 ms)
* Your runtime beats 97.54 % of javascript submissions
* Your memory usage beats 46.88 % of javascript submissions (43.2 MB)
可以看到,时间超大幅度提升,空间较前面有所减少,牺牲了空间换来了时间的优化。
以上,就是本题的解法。
如果你有更好的想法或者思路,欢迎评论留言或者私聊~
不折腾的前端,和咸鱼有什么区别!
jsliang 会每天更新一道 LeetCode 题解,从而帮助小伙伴们夯实原生 JS 基础,了解与学习算法与数据结构。
浪子神剑 会每天更新面试题,以面试题为驱动来带动大家学习,坚持每天学习与思考,每天进步一点!
扫描上方二维码,关注 jsliang 的公众号(左)和 浪子神剑 的公众号(右),让我们一起折腾!
jsliang 的文档库 由 梁峻荣 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
基于https://github.com/LiangJunrong/document-library上的作品创作。
本许可协议授权之外的使用权限可以从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处获得。