「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!」
前言
最近空闲的时候就在lettcode刷题,下面把自己刷的题以及自己的解法总结一下。
最长回文子串
描述:给你一个字符串 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次,参数不一样,一个当前下标,一个当前下标加一,因为回文有可能是奇数,或者偶数。
- 找到后对比哪个最大,最后返回
最长公共前缀
描述:编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。
注意:这里说的是前缀
输入: 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就是最长的公共前缀
无重复字符的最长子串
描述:给定一个字符串 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中,直到有重复的为止。 - 一次遍历后对
res和innerRes比较长度,如果innerRes大,则赋值给res, 接着继续下次遍历 - 最后返回
res
青蛙跳台阶问题
描述:一只青蛙一次可以跳上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
只出现一次的数字
描述:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
输入: [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]
}
};
解析:
- 首先对数组排序,从小排到大,然后对数组遍历
- 然后判断如果第一个元素不等于下一个元素 则找到,然后返回该元素
- 否则然后判断如果最后一个元素不等于前一个元素 则找到,然后返回该元素
- 否则判断元素和前后元素是否相等,如果不等,则找到,返回该元素,否则继续遍历。
总结
以上就是最近刷题的题目和自己的答案,我的答案只是代表了我的思路,大家有空也可以做一下,看有没有更优的解法,欢迎大家评论留言自己的解法,谢谢。