前言
最近,我的一个好朋友正在换工作。她选择成为一名程序员,非常出色和自信,但在最近的面试中遭遇了巨大的挫折。
面试官对她说:“你已经工作了两年,居然不能解决这两个问题?” 什么样的面试题会让面试官对某人如此粗鲁地说话呢?
1. Two Sum
提示: 这是 LeetCode 上的原题,点击 这里 查看。
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的两个整数。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
你可以按任意顺序返回答案。
示例 1:
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].
示例 2:
Input: nums = [3,2,4], target = 6
Output: [1,2]
示例 3:
Input: nums = [3,3], target = 6
Output: [0,1]
约束条件:
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只存在一个有效答案。
2.1. 使用两个“for”循环解决问题
当我的朋友看到这个问题时,她觉得自己很幸运,因为它似乎很容易。于是她马上写下了答案,等待面试官问下一个问题。
她的答案是:
const twoSum = (nums, target) => {
const len = nums.length
for (let i = 0; i < len; i++) {
// j = i + 1, Because the same element cannot be repeated in the answer
for (let j = i + 1; j < len ; j++) {
// find the answer, return
if (nums[ i] + nums[ j ] === target) {
return [ i, j ]
}
}
}
}
面试官对她的快速回答表示赞赏,但他对结果不是很满意,认为可能还有进一步的优化空间。
2.2. 使用“Map”解决问题
通常情况下,使用两个“for”循环来解决问题时,我们需要意识到算法的时间复杂度(O(n2))可能会得到优化。
实际上,我们可以使用一个“for”循环来完成,只要将加法变成减法,并将遍历的值存储在对象 sumCache
中即可。
例如:
输入:[2,7,11,15]
步骤1
Read 2 and "sumCache" is empty. Store 2 as the key and index 0 as the value in "sumCache"
步骤2
Read 7 and find that the target value is 9 - 7 = 2.
If 2 exists in "sumCache", the 0 and 1 indexes will be returned directly
你觉得使用“Map”的方法简单明了,比 for 循环容易得多吗?
const twoSum = (nums, target) => {
const len = nums.length
const sumCache = {}
for (let i = 0; i < len; i++) {
const value = nums[ i ]
// Calculate the diff
const diff = target - value
// If the diff already exists, return the corresponding index directly
if (typeof sumCache[ diff ] !== 'undefined') {
return [ sumCache[ diff ], i ]
} else {
// otherwise save the value and index
sumCache[ value ] = i
}
}
}
太好了。我们得到了更好的结果。我们只使用了额外的 1.5M 空间,将时间减少了近一半,
3. 如何防止多次重复发送请求?
3.1. 问题信息
在工作中,通常需要仅发送一次请求,以防止用户重复点击。
请传入请求方法(执行后返回 Promise)并返回一个新方法。在连续触发时,仅发送一个请求。
示例:
function firstPromise () {
// ...Please fill in here
}
let count = 1;
let promiseFunction = () =>
new Promise(rs =>
window.setTimeout(() => {
rs(count++)
})
)
let firstFn = firstPromise(promiseFunction)
firstFn().then(console.log) // 1
firstFn().then(console.log) // 1
firstFn().then(console.log) // 1
3.2. 问题分析
与算法问题相比,这个问题相对容易,我们只需要利用闭包和“Promise”的特性即可完成。
function firstPromise(promiseFunction) {
// Cache request instance
let p = null
return function (...args) {
// If the requested instance already exists, it means that the request is in progress, return the instance directly without triggering a new request
return p
? p
// Otherwise send the request and set p to null at the end of the Promise, then the next request can be resent
: (p = promiseFunction.apply(this, args).finally(() => (p = null)))
};
}
测试:
let count = 1
let promiseFunction = () =>
new Promise((rs) =>
setTimeout(() => {
rs(count++)
}, 1000)
)
let firstFn = firstPromise(promiseFunction)
firstFn().then(console.log) // 1
firstFn().then(console.log) // 1
firstFn().then(console.log) // 1
setTimeout(() => {
firstFn().then(console.log) // 2
firstFn().then(console.log) // 2
firstFn().then(console.log) // 2
}, 3000)
评论(0)