LeetCode萌新前端刷题记录

741 阅读3分钟

简单篇

7.整数反转

思路

  1. 反转:使用JS数组的reverse方法 or 手动倒序取值
  2. 区间:使用Match.pow函数得到n次方值
  3. 负数:反转过程中用绝对值计算,最后判断原数值是否小于0手动补负号

代码实现

function reverse(x: number): number {
    // Math.abs(x) 取绝对值
    // -> toString().split('') 转字符串后再转数组
    // -> reverse().join() 反转后再拼接
    const temp = Math.abs(x).toString().split('').reverse().join('')
    // 字符串转数值型
    let result = Number(temp)
    // 手动补负号
    if (x < 0) {
        result = - result
    }
    // 两个区间
    const min = - Math.pow(2, 31)
    const max = Math.pow(2, 31) - 1
    // 按题意判断
    return min <= result && result <= max ? result : 0
};

9.回文数

思路

  1. 将数值转换为字符串
  2. 找到中间点midIndex将字符串分割为长度等分的两组
  3. midIndex确定:midIndex = len / 2 因为向下取整的关系,对于奇数个是准确找到中间值下标的,对于偶数个就需要-1分割
  • 奇数个: 5 / 2 = 2 => [1,2,3,4,5] 中间点划下标 2 => 中间值 3 以中间值左右两侧划分[0,midIndex-1],中间值,[midIndex+1,length-1] 代码实现则是slice(0, midIndex),slice(midIndex+1, length),slice 前闭后开
  • 偶数个:4 / 2 = 2 => [1,2,3,4] 中间点划分下标 [2-1,2] = [midIndex-1,midIndex] => 中间值 2,3 直接中间对半分割[0,midIndex-1],[midIndex, length] 代码实现则是slice(0, midIndex),slice(midIndex, length),slice 前闭后开

代码实现

function isPalindrome(x: number): boolean {
    const strArr = x.toString().split('')
    const numStrLen = strArr.length

    if (numStrLen === 1) return true
    if (numStrLen === 2) return strArr[0] === strArr[1]

    const midIndex = numStrLen / 2
    const str1 = strArr.slice(0, midIndex)
    const str2 = strArr.slice(numStrLen % 2 ? midIndex + 1 : midIndex, numStrLen)
    
    return str1.join('') === str2.reverse().join('')
};

20.有效的括号

思路

借用栈的特性(先进后出),对目标字符串进行逐字符串拆分,遍历拆分后的字符串组,若是匹配组开头字符则推入栈中,若不是则代表当前字符是结尾字符,即栈中的最后一个字符应该与当前字符为头尾匹配,若匹配成功则栈内最后一个元素出栈,若匹配失败则表明字符串不合法。

代码实现

function isValid(s: string): boolean {
    let stack = []
    let invalidTag = false
    const strArr = s.split('')
    const matchCase = {"[": "]", "(": ")", "{": "}"}

    // 奇数位一定不能正确匹配
    if (strArr.length % 2 > 0) {
        return false
    }

    for(let i in strArr) {
        const item = strArr[i]
        const itemMtachChar = matchCase[item]

        if (itemMtachChar) {
            // 是开头字符,直接入栈
            stack.push(item)
        } else if (matchCase[stack.pop()] !== item) {
            // 不是开头字符,判断与栈内最后一个元素是否匹配
            invalidTag = true
            break
        }
    }

    return invalidTag ? false : stack.length === 0
};

14.最长公共前缀

思路

详细思路见下方代码注释

取第一个元素作为比较的标准对象string类型),遍历传入数组(循环索引i),标准对象逐位截取(循环索引j),传入数组[i][j](第i+1个元素的前j+1位字符)和标准对象[j](标准对象的前j+1位字符)进行比较,若不满足条件则停止循环,标准对象的前j-1位字符便是公共前缀。

注意点:

  1. 为了减少循环次数,一旦循环过程中有出现过无公共前缀的情况,即可以直接返回结果,不用进行后续无用的比较。
  2. 将传入数组的第一个元素作为比较标准对象,后续逐位的字符串比较,每次当前传入字符串和标准对象比较完成后,都基于当前得出的公共前缀索引对标准对象字符串进行截取更新。因为比较标准在每一次比较完一个传入字符串时都会更新,那么下一次比较开始前,比较范围已经得到缩小(是基于上一次比较成功的结果上再进行比较)。

代码实现

function longestCommonPrefix(strs: string[]): string {
  // 特殊情况处理
  if (strs.length <= 1) {
    return strs[0] || "";
  }
  // 公共前缀:取第1个元素作为比较标准
  let commPrefix = strs[0];

  // 从第2个元素开始遍历比较
  for (let i = 1; i < strs.length; i++) {
    // 用index作下标标记,逐位截取target进行字符串比较
    let index = 0;
    // 当前被比较字符串 strs[i] => 字符串的前 index+1 个字符 和 公共前缀的前 index+1 个字符进行比较
    for (; index < commPrefix.length && index < strs[i].length; index++) {
      // index会一直递增,直到遇到不满足的情况就跳出循环停止递增
      if (strs[i][index] !== commPrefix[index]) {
        break;
      }
    }
    // 停止循环时的index是不满足条件的index,所以前一位 index-1 才是满足条件的
    // substring 刚好是前开后闭,满足我们 index-1 的场景
    commPrefix = commPrefix.substring(0, index);
    // 初始 commPrefix 是 target,根据每次得出的index进行截取更新,若后一轮得出的index比上一轮大,
    // 则截取结果不会发生,便满足公共前缀的需求
    // e.g. 1: abc vs. abcd => abc; 2: abc vs. ab => ab; final: abc vs. ab => ab

    // 一旦得出过没有匹配的前缀之后,可以直接返回结果,后续不用再比较
    if (commPrefix === "") {
      break;
    }
  }

  return commPrefix;
}