无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列, 不是子串。
示例 4:
输入: s = ""
输出: 0
提示:
0 <= s.length <= 5 * 104s由英文字母、数字、符号和空格组成
解题
维护数组:
遍历字符串,判断字符是否在滑动窗口数组里
- 不在则 push 进数组
- 在则删除滑动窗口数组里相同字符及相同字符前的字符,然后将当前字符 push 进数组
- 然后将 max 更新为当前最长子串的长度
var lengthOfLongestSubstring = function(s) {
let arr = [];
let max_len = 0;
s = s.split('');
for(let i=0; i<s.length; i++){
let index = arr.indexOf(s[i]);
if(index !== -1){
arr.splice(0,index+1);
}
arr.push(s[i]);
// 比较获得最长substring
max_len = Math.max(arr.length,max_len);
}
return max_len
};
最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""。
示例 1:
输入: strs = ["flower","flow","flight"]
输出: "fl"
示例 2:
输入: strs = ["dog","racecar","car"]
输出: ""
解释: 输入不存在公共前缀。
提示:
1 <= strs.length <= 2000 <= strs[i].length <= 200strs[i]仅由小写英文字母组成
解题
又 见 暴力破解
var longestCommonPrefix = function(strs) {
let compare = strs[0];
for(let i=1; i<strs.length; i++){
if(strs[i].length < compare.length){
compare = strs[i];
}
}
let result = "";
for(let i=0; i<compare.length; i++){
let j=0
for(; j<compare.length && j<strs[j].length; j++){
if(compare.charAt(j) !== strs[j].charAt(j)) break
}
result = compare.substring(0,j);
}
if(result === '') return "";
else return result;
};
字符串的排列
给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 ****的排列。如果是,返回 true ;否则,返回 false 。
换句话说,s1 的排列之一是 s2 的 子串 。
示例 1:
输入: s1 = "ab" s2 = "eidbaooo"
输出: true
解释: s2 包含 s1 的排列之一 ("ba").
示例 2:
输入: s1= "ab" s2 = "eidboaoo"
输出: false
提示:
1 <= s1.length, s2.length <= 104s1和s2仅包含小写字母
解题
参考剑指offer38: 字符串的排序
先用dfs得到 s1 所有的排序,随后用String.prototype.includes()搜索s2
/**
* @param {string} s1
* @param {string} s2
* @return {boolean}
*/
var checkInclusion = function(s1, s2) {
function permutation(s){
let arr = s1.split('');
let len = s1.length;
let flag = []; // 记录是否被遍历过
let str = []; // 每次遍历的结果
let result = []; // 最终所有遍历的结果
function dfs(node){
// 已遍历至最终节点
if(node === len){
// 将结果推入数组储存
result.push(str.join(''));
// 结束循环
return
}
for(let i=0; i<len; i++){
if(!flag[i]){
str[node] = arr[i];
flag[i] = 1;
// 进入下一层
dfs(node + 1);
flag[i] = 0;
}
}
}
// 从0开始遍历
dfs(0);
return result;
}
let list = permutation(s1);
for(let i=0; i<list.length; i++){
if(s2.includes(list[i])){
return true
}
}
return false;
};
字符串相乘
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
示例 1:
输入: num1 = "2", num2 = "3"
输出: "6"
示例 2:
输入: num1 = "123", num2 = "456"
输出: "56088"
说明:
num1和num2的长度小于110。num1和num2只包含数字0-9。num1和num2均不以零开头,除非是数字 0 本身。- 不能使用任何标准库的大数类型(比如 BigInteger) 或直接将输入转换为整数来处理。
解题
e.g. 11 = 1*1 + 10*1 + 10+1 + 10*10
var multiply = function(num1, num2) {
let n1 = num1.split('');
let n2 = num2.split('');
let result = [];
for(let i=0; i<n1.length; i++){
for(let j=0; j<n2.length; j++){
let each = (n1[i]*Math.pow(10,i))*(n2[j]*Math.pow(10,j));
result.push(each);
}
}
return (eval(result.join('+')));
};
翻转字符串里的单词
给你一个字符串 s ,逐个翻转字符串中的所有 单词 。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
请你返回一个翻转 s 中单词顺序并用单个空格相连的字符串。
说明:
- 输入字符串
s可以在前面、后面或者单词间包含多余的空格。 - 翻转后单词间应当仅用一个空格分隔。
- 翻转后的字符串中不应包含额外的空格。
示例 1:
输入: s = "the sky is blue"
输出: "blue is sky the"
示例 2:
输入: s = " hello world "
输出: "world hello"
解释: 输入字符串可以在前面或者后面包含多余的空格,但是翻转后的字符不能包括。
示例 3:
输入: s = "a good example"
输出: "example good a"
解释: 如果两个单词间有多余的空格,将翻转后单词间的空格减少到只含一个。
示例 4:
输入: s = " Bob Loves Alice "
输出: "Alice Loves Bob"
示例 5:
输入: s = "Alice does not even like bob"
输出: "bob like even not does Alice"
提示:
1 <= s.length <= 104s包含英文大小写字母、数字和空格' 's中 至少存在一个 单词
进阶:
- 请尝试使用
O(1)额外空间复杂度的原地解法。
解题
/**
* @param {string} s
* @return {string}
*/
var reverseWords = function(s) {
return s.split(' ').filter(words => words !== '').reverse().join(' ')
};
简化路径
给你一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 '/' 开头),请你将其转化为更加简洁的规范路径。
在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。任意多个连续的斜杠(即,'//')都被视为单个斜杠 '/' 。 对于此问题,任何其他格式的点(例如,'...')均被视为文件/目录名称。
请注意,返回的 规范路径 必须遵循下述格式:
- 始终以斜杠
'/'开头。 - 两个目录名之间必须只有一个斜杠
'/'。 - 最后一个目录名(如果存在)不能 以
'/'结尾。 - 此外,路径仅包含从根目录到目标文件或目录的路径上的目录(即,不含
'.'或'..')。
返回简化后得到的 规范路径 。
示例 1:
输入: path = "/home/"
输出: "/home"
解释: 注意,最后一个目录名后面没有斜杠。
示例 2:
输入: path = "/../"
输出: "/"
解释: 从根目录向上一级是不可行的,因为根目录是你可以到达的最高级。
示例 3:
输入: path = "/home//foo/"
输出: "/home/foo"
解释: 在规范路径中,多个连续斜杠需要用一个斜杠替换。
示例 4:
输入: path = "/a/./b/../../c/"
输出: "/c"
提示:
1 <= path.length <= 3000path由英文字母,数字,'.','/'或'_'组成。path是一个有效的 Unix 风格绝对路径。
解题
/**
* @param {string} path
* @return {string}
*/
var simplifyPath = function(path) {
path = path.split('/');
let ans = [];
for(let i=0; i<path.length; i++){
if(path[i] ==='..') {
ans.pop();
}
else if(path[i]===''||path[i]==='.')
continue;
else{
ans.push(path[i]);
}
}
if(ans.length === 0){
return '/';
}
else{
let result = '/' + ans.join('/');
return result;
}
};
复原 IP 地址
有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。
- 例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效 IP 地址。
给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你不能重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
示例 1:
输入: s = "25525511135"
输出: ["255.255.11.135","255.255.111.35"]
示例 2:
输入: s = "0000"
输出: ["0.0.0.0"]
示例 3:
输入: s = "1111"
输出: ["1.1.1.1"]
示例 4:
输入: s = "010010"
输出: ["0.10.0.10","0.100.1.0"]
示例 5:
输入: s = "101023"
输出: ["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]
提示:
0 <= s.length <= 20s仅由数字组成
解题
/**
* @param {string} s
* @return {string[]}
*/
var restoreIpAddresses = function(str) {
// 当前这里可以加一个判断 字符串的条件,字符串长度必须大于等于 4
// 保存所有符合条件的 IP 地址
let s = []
let search = (cur, sub) => {
// 递归的边界条件,数组长度等于 4 且组合起来与之前的字符串相等
if (cur.length === 4 && cur.join('') === str) {
s.push(cur.join('.'))
} else {
// 处理正常过程
// 每次最多循环三次
let len = Math.min(3, sub.length)
for (let i = 0; i < len; i++) {
// 截取字符串 1 ~ 3
let tmp = sub.substr(0, i + 1)
// 如果当前的数小于 256 说明在 255 范围内,接着递归调用(把不是范围内的排出掉)
// 例如 255255255, 截取第一次 2,第二次递归截取时 for循环第三次是 522 不在范围内
if(tmp < 256) {
search(cur.concat([tmp]), sub.substr(i + 1))
}
}
}
}
search([], str)
return s
};