最近刷题的合集(附解法)

325 阅读3分钟

「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!

前言

最近空闲的时候就在lettcode刷题,下面把自己刷的题以及自己的解法总结一下。

最长回文子串

leetcode地址

描述:给你一个字符串 s,找到 s 中最长的回文子串。 (回文子串就是正着读和反着读都是一样的)

输入: s = "babad"
输出: "bab"

输入: s = "cbbd"
输出: "bb"

输入: s = "a"
输出: "a"

题解1:

/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function(s) {
  if(s.length === 1) return s
  let str = ''
  for(let i = 0; i < s.length; i++) {
    let index = s.indexOf(s[i], i + 1)
    while (index > -1) {
      let j = i
      let idx = index
      while(j < idx && s[++j] === s[--idx]) {}
      const sliceStr = s.slice(i, index + 1)
      if((j === idx || j === idx + 1) && sliceStr.length > str.length) str = sliceStr
      index = s.indexOf(s[i], index + 1)
    }
  }
  return str || s[0]
}

解析:

  • 首先是对字符串s遍历,当前遍历的下标是i,寻找下一个跟当前遍历的字符串一样的元素的下标index
  • 如果找不到,则继续遍历,如果找到,进入while循环,在while循环中,i赋值给j,j递增,index递减,判断元素是否相等,直到不相等或者j大于或者等于idx,则退出
  • 退出后判断j是否和idx相等(回文是奇数),或者j等于idx + 1(回文是偶数),如果true就是回文字符串
  • 继续下次遍历,直到找到最长的。

这个方法不是最优的,因为我这里使用for循环嵌套两次while循环。

下面看另一个更好的解法:

题解2:

var longestPalindrome = function (s) {
  if (s.length === 1) return s;
  let maxRes = 0, maxStr = '';
  for (let i = 0; i < s.length; i++) {
    let str1 = findPalindrome(s, i, i);
    let str2 = findPalindrome(s, i, i + 1);
    if (str1.length > maxRes) {
      maxStr = str1;
      maxRes = str1.length;
    }
    if (str2.length > maxRes) {
      maxStr = str2;
      maxRes = str2.length;
    }
  }
  return maxStr;
};
function findPalindrome (s, l, r) {
  while (l >= 0 && r < s.length && s[l] === s[r]) {
    l--;
    r++;
  }
  return s.slice(l + 1, r);
}

解析:

  • 首先是对字符串s遍历,然后对遍历的元素,去找回文字符串,这里是创建一个findPalindrome函数专门来找回文字符串
  • findPalindrome函数对当前传入的下标,同时往前往后去找回文字符串,直到前后元素不相等,这时候找到的就是回文字符串
  • 这里会调用 findPalindrome函数2次,参数不一样,一个当前下标,一个当前下标加一,因为回文有可能是奇数,或者偶数。
  • 找到后对比哪个最大,最后返回

最长公共前缀

leetcode地址

描述:编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""

注意:这里说的是前缀

输入: strs = ["flower","flow","flight"]
输出: "fl"

输入: strs = ["dog","racecar","car"]
输出: ""

题解:

/**
 * @param {string[]} strs
 * @return {string}
 */
var longestCommonPrefix = function (strs) {
  if (strs.length <= 0) return ''
  let res = ''
  strs.sort((a, b) => a.length - b.length)
  let str = strs[0]
  for (let i = 0; i < str.length; i++) {
    let checkStr = str.slice(0, i + 1)
    if (strs.slice(1).every(item => item.slice(0, i + 1) === checkStr) && res.length < checkStr.length) res = checkStr
  }
  return res
}

解析:

  • 首先对字符串数组排序,根据字符串长度从小到大排,这时候第一个是最短的
  • 然后取数组第一个字符串,遍历这个字符串,取这个字符串从头开始的子字符串,去和后面数组的字符串比较,如果都想相等,则继续遍历,直到不相等。
  • 这时候res就是最长的公共前缀

无重复字符的最长子串

leetcode地址

描述:给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3

题解:

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function (s) {
  let res = ''
  for (let i = 0; i < s.length; i++) {
    let innerRes = ''
    while (!innerRes.includes(s[i])) {
      for (let j = i; j < s.length; j++) {
        if (!innerRes.includes(s[j])) {
          innerRes += s[j]
        } else {
          break
        }
      }
      break
    }
    if (res.length < innerRes.length) res = innerRes
  }
  return res.length
}

解析:

  • 顶部声明一个res,然后对字符串进行遍历,每次都声明一个变量innerRes, 用来存储无重复字符
  • 如果innerRes没有重复的字符串,则对当前下标后的字符串一直遍历,把字符串赋值到innerRes中,直到有重复的为止。
  • 一次遍历后对resinnerRes比较长度,如果innerRes大,则赋值给res, 接着继续下次遍历
  • 最后返回res

青蛙跳台阶问题

leetcode地址

描述:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。 答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。


输入: n = 0
输出: 1

输入: n = 1
输出: 1

输入: n = 2
输出: 2

输入: n = 3
输出: 3

题解:

/**
 * @param {number} n
 * @return {number}
 */
var numWays = function (n) {
  var p = q = 0; r = 1;
  for (let i = 0; i < n; i++) {
    p = q
    q = r
    r = (p + q) % 1000000007
  }
  return r
}

解析:

  • 你上一级台阶,只有1种走法,你上二级台阶,有2种走法,你上3级台阶,相当于上一级台阶和二级台阶的走法的总和(因为你可以先走一级,后面再走二级,也可以先走2级,再走一级),这就是著名的斐波那契数列,前面2个数的和等于后面的数,依此类推。
  • 所以这里我们声明了p,q,r三个变量。
  • 然后遍历n次,对他们替换赋值,然后取和。题目要求取模。
  • 返回 r

只出现一次的数字

leetcode地址

描述:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

输入: [2,2,1]
输出: 1

输入: [4,1,2,1,2]
输出: 4

题解:

/**
 * @param {number[]} nums
 * @return {number}
 */
var singleNumber = function (nums) {
  nums.sort((a, b) => a - b)
  for (let i = 0; i < nums.length; i++) {
    if ((i === 0 && nums[i] !== nums[i + 1]) || i === nums.length - 1 && nums[i - 1] !== nums[i]) return nums[i]
    if (nums[i] !== nums[i - 1] && nums[i] !== nums[i + 1]) return nums[i]
  }
};

解析:

  • 首先对数组排序,从小排到大,然后对数组遍历
  • 然后判断如果第一个元素不等于下一个元素 则找到,然后返回该元素
  • 否则然后判断如果最后一个元素不等于前一个元素 则找到,然后返回该元素
  • 否则判断元素和前后元素是否相等,如果不等,则找到,返回该元素,否则继续遍历。

总结

以上就是最近刷题的题目和自己的答案,我的答案只是代表了我的思路,大家有空也可以做一下,看有没有更优的解法,欢迎大家评论留言自己的解法,谢谢。