前端算法面试必刷题系列[3]

396 阅读3分钟

这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。

封面选的好,点赞少不了。^ - ^

7. 罗马数字转整数 (roman-to-integer)

标签

  • Map
  • 简单

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

给定一个罗马数字,将其转换成整数。简单题咱就也简单说,不浪费时间。

基本知识

罗马数字的字符表示和一些特殊表示法,都在题干里。

基本思路

  1. 创建罗马数和整数的映射关系对象
  2. 按照一个字母还是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 传送门

这里不贴题了,leetcode打开就行,题目大意:

给定一个数组,要求在这个数组中找出 3 个数之0所有组合。本题的难点在于如何去除重复解

基本知识

这个问题可以用各种数学方法优化它,整体来说是个双指针。

基本思路

  1. 特判,如果数组为 null 或者数组长度小于 3,直接返回 []。
  2. 对数组进行排序。
  3. 遍历排序后数组:
    • 每一轮的这个 i 是确定的,左右指针向中间移动来匹配
    • nums[i] > 0,因为已经排序好,所以后面三个数加必大于 0,直接返回
    • 对于重复元素:直接跳过本轮循环,避免出现重复解
    • 令左指针 left=i+1,右指针 right=len−1,当 left<right 时,执行循环:
      1. nums[i] + nums[L] + nums[R] === 0 ,执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将左右指针向中间移到下一位置,寻找新的解
      2. 和大于 0 的情况,说明 nums[right] 太大,right 左移
      3. 和小于 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 传送门

这里不贴题了,leetcode打开就行,题目大意:

给定一个数组,要求在这个数组中找出 3 个数之和离 target 最近。

基本知识

  • 跟上面的三数之和基本相同哈

基本思路

和上面一个问题几乎相同的思路,左右指针夹逼,求最小距离。写法也差不多

  1. 先排序,有序数组才能使用双指针夹逼
  2. 每轮有一个 i, 和为 nums[i] 加左右指针指向的,和当前最小距离diff比较,取最小
  3. 遍历之后 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,我看到就通过,暗号对不上不加哈