这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。
封面选的好,点赞少不了。^ - ^
7. 罗马数字转整数 (roman-to-integer)
标签
- Map
- 简单
题目
这里不贴题了,leetcode打开就行,题目大意:
给定一个罗马数字,将其转换成整数。简单题咱就也简单说,不浪费时间。
基本知识
罗马数字的字符表示和一些特殊表示法,都在题干里。
基本思路
- 创建罗马数和整数的映射关系对象
- 按照一个字母还是2个字母的映射关系做映射,之后相加合。
写法实现
/**
* @param {string} s
* @return {number}
*/
var romanToInt = function(s) {
// 创建罗马数和整数的映射关系对象
let map = { 'I': 1, 'IV': 4, 'V': 5, 'IX': 9, 'X': 10, 'XL': 40, 'L': 50, 'XC': 90, 'C': 100, 'CD': 400, 'D': 500, 'CM': 900, 'M': 1000 };
let sum = 0;
for (let i = 0, len = s.length; i < len; i++) {
// 这边操作就是因为有可能是2字母 没什么花头 随意实现
let muitple = s[i] + s[i + 1];
let single = s[i];
// 如果后面一个字母组合没有,说明是单个字符位
if (map[muitple] == undefined) {
sum += map[single];
} else {
sum += map[muitple];
i++
}
}
return sum
};
8. 三数之和 (3sum)
标签
- Array
- 双指针
- 排序
- 中等
题目
这里不贴题了,leetcode打开就行,题目大意:
给定一个数组,要求在这个数组中找出 3 个数之和为 0 的所有组合。本题的难点在于如何去除重复解。
基本知识
这个问题可以用各种数学方法优化它,整体来说是个双指针。
基本思路
- 特判,如果数组为 null 或者数组长度小于 3,直接返回 []。
- 对数组进行排序。
- 遍历排序后数组:
- 每一轮的这个
i是确定的,左右指针向中间移动来匹配 - 若
nums[i] > 0,因为已经排序好,所以后面三个数加必大于 0,直接返回 - 对于重复元素:直接跳过本轮循环,避免出现重复解
- 令左指针
left=i+1,右指针right=len−1,当left<right时,执行循环:- 当
nums[i] + nums[L] + nums[R] === 0,执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将左右指针向中间移到下一位置,寻找新的解 - 和大于 0 的情况,说明
nums[right]太大,right 左移 - 和小于 0 的情况,说明
nums[left]太小,left 右移
- 当
- 每一轮的这个
写法实现
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
let [res, len, left, right, tempSum] = [[], nums.length, 0, 0, 0]
// 先排序
nums = nums.sort((a, b) => a - b)
// 特殊判定 对于数组长度 nn,如果数组为 null 或者数组长度小于 3,直接返回 []
if (!nums || len < 3) {
return []
}
for (let i = 0; i < len; i++) {
// 每一轮其实这个 i 是确定的,左右指针向中间移动来匹配
// 若 nums[i]>0,因为已经排序好,所以后面不可能有三个数加和等于 0,直接返回
if (nums[i] > 0) {
return res
}
// 发现元素重复,直接跳过本轮循环
if (i > 0 && nums[i] === nums[i-1]) {
continue;
}
// 左右指针,开始时指向边界
left = i + 1
right = len - 1
while (left < right) {
// 这是每次求和的中间变量
tempSum = nums[i] + nums[left] + nums[right]
if (tempSum === 0) {
// 和等于 满足条件 进结果数组
res.push([nums[i], nums[left], nums[right]])
// 判断左界和右界是否和下一位置重复,去除重复解。
while (left < right && nums[left] === nums[left+1]) {
left++
}
while (left < right && nums[right] === nums[right-1]) {
right--
}
// 并同时将 left,right 移到下一位置,寻找新的解
left++
right--
} else if (tempSum > 0) {
// 和大于 0 的情况,说明 nums[right] 太大,right 左移
right--
} else {
// 和小于 0 的情况,说明 nums[left] 太小,left 右移
left++
}
}
}
return res
};
console.log(threeSum([-1,0,1,2,-1,-4]))
9. 最接近的三数之和 (3sum-closest)
标签
- Array
- 双指针
- 排序
- 中等
题目
这里不贴题了,leetcode打开就行,题目大意:
给定一个数组,要求在这个数组中找出 3 个数之和离 target 最近。
基本知识
- 跟上面的三数之和基本相同哈
基本思路
和上面一个问题几乎相同的思路,左右指针夹逼,求最小距离。写法也差不多
- 先排序,有序数组才能使用双指针夹逼
- 每轮有一个
i, 和为nums[i]加左右指针指向的值,和当前最小距离diff比较,取最小 - 遍历之后 diff最近的一组和就是res输出结果
写法实现
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var threeSumClosest = function(nums, target) {
// diff 是当前和sum与target的举距离
let [len, res, diff] = [nums.length, 0, Infinity]
// 先排序
if (len > 2) {
nums = nums.sort((a, b) => a - b)
for (let i = 0; i < len - 2; i++) {
let left = i + 1
let right = len - 1
while (left < right) {
let sum = nums[i] + nums[left] + nums[right]
// 比较获取当前最小diff
if (Math.abs(sum - target) < diff) {
// 如果和比当前最小距离还小,就把res,和diff都替换
res = sum
diff = Math.abs(sum - target)
}
if (sum === target) {
return res
} else if (sum > target) {
// 如果当前和大于target,右指针左移,因为这是排序好的数组,和会变小
right--
} else {
left++
}
}
}
}
return res
};
console.log(threeSumClosest([-1,2,1,-4], 1))
今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦
搜索我的微信号infinity_9368,可以聊天说地
加我暗号 "天王盖地虎" 下一句的英文,验证消息请发给我
presious tower shock the reiver monster,我看到就通过,暗号对不上不加哈