最长系列
# 最长系列
[TOC]
# 一、3 - 无重复字符的最长子串
# 1.1 题目
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
1
2
3示例 2:
输入: "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
1
2
3示例 3:
输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
1
2
3
4
# 1.2 题解
# 1.2.1 滑动窗口法
- 维护一个滑动窗口,窗口内的都是没有重复的字符,去尽可能的扩大窗口的大小,窗口不停的向右滑动。
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let res = [] // 窗口
let max = 0 // 最大窗口长度
for(let item of s) {
if(res.indexOf(item) !== -1) {
res.splice(0, res.indexOf(item)+1) // 窗口左边框左移
}
res.push(item) // 窗口右边框右移
max = Math.max(max, res.length)
}
return max
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 二、5-最长回文字符串
# 2.1 题目
给定一个字符串 s
,找到 s
中最长的回文子串。你可以假设 s
的最大长度为 1000。
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
1
2
3
2
3
# 2.2 题解
- 状态:
dp[i][j]
表示子串s[i][j]
是否为回文子串。 - 状态转移方程:
dp[i][j] = (s[i] == s[j]) and da[i+1][j-1]
- 边界条件:当j - 1 - ( i + 1) + 1 < 2 时不需要检查子串是否回文
- 整理,得 j - i < 3 -> j - i + 1 < 4
- 即,是
s[i..j]
长度为2或3时,不用检查子串是否回文。
- 初始化:
dp[i][i] = true
- 输出:在得到一个状态的值为true的时候,记录起始位置和长度,填完表以后再截取。
# 三、14-最长公共前缀(longest-common-prefix)
# 3.1 题目
编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。
示例 1:
输入: ["flower","flow","flight"] 输出: "fl" 示例 2:输入: ["dog","racecar","car"] 输出: "" 解释: 输入不存在公共前缀。 说明:所有输入只包含小写字母 a-z 。
# 3.2 题解
- 特殊情况的考虑
- 字符串数组为空
- 字符串数组只有一个字符串
# 3.1 水平扫描法
- 思路
- 先找到长度最短的字符串,再从中匹配前缀。
- 扫描最短字符串的每一个字符,依次匹配第一个字符是不是公共的,第二个字符是不是公共的...
var longestCommonPrefix = function (strs) {
if (!strs.length) return '';
if (strs.length === 1) return strs[0];
let len = strs.length;
let prefix = strs[0];
for (let i = 0; i < len - 1; i++) {
if (strs[i].length > strs[i + 1].length) {
prefix = strs[i + 1];
}
}
for (let i = 0; i < prefix.length; i++) {
for (let j = 0; j < len; j++) {
if (prefix[i] !== strs[j][i]) {
return prefix.substring(0, i);
}
}
}
return prefix;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 复杂度分析
时间复杂度:O(S),S 是所有字符串中字符数量的总和。
- 最坏情况下,输入数据为 n 个长度为 m 的相同字符串,算法会进行 S = mn 次比较。最好的情况下,算法只需要进行 nstr[0].length次比较,即最长前缀为空时。
空间复杂度:O(1),我们只需要使用常数级别的额外空间。
# 2.2 reduce()大法
先找出第一个和第二个的最长前缀,再找出前一个最长前缀与下一个的最长前缀...
var longestCommonPrefix = function (strs) {
if (!strs.length) return '';
if (strs.length==1) return strs[0];
return strs.reduce((prev,next)=>{
let i = 0;
while(prev[i]&&next[i]&&prev[i]===next[i]){
i++;
}
return prev.slice(0,i);
})
};
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12