Reverse string
2020.09.01
No.344 Reverse character string
Write a function whose role is to reverse the input string. The input string is given in the form of a character array char[].
Don't allocate extra space for another array, you must modify the input array in place and use O(1) extra space to solve this problem.
You can assume that all characters in the array are printable characters in the ASCII code table.
Example 1:
Input: ["h","e","l","l","o"]
Output: ["o","l","l","e","h"]
Example 2:
Input: ["H","a","n","n","a","h"]
Output: ["h","a","n","n","a","H"]
Source: LeetCode
Link: https://leetcode-cn.com/problems/reverse-string
The copyright belongs to Lingkou Network. For commercial reprints, please contact the official authorization. For non-commercial reprints, please indicate the source.
Option One:
/*
* @lc app=leetcode.cn id=344 lang=javascript
*
* [344] 反转字符串
*/
// @lc code=start
/**
* @param {character[]} s
* @return {void} Do not return anything, modify s in-place instead.
*/
var reverseString = function(s) {
return s.reverse()
};
Option II:
/*
* @lc app=leetcode.cn id=344 lang=javascript
*
* [344] 反转字符串
*/
// @lc code=start
/**
* @param {character[]} s
* @return {void} Do not return anything, modify s in-place instead.
*/
var reverseString = function(s) {
let i = 0,
x = s.length -1;
while (i < x) {
[s[i], s[x]] = [ s[x], s[i] ]
i++
x--
}
};
There are three solutions: 1. Use its own reverse() api; 2. Use double pointers for input and output exchange; 3. Use recursion for input and output exchange
2020.09.02
No.345 Reverse vowels in a character string
Write a function that takes a string as input and reverses the vowels in the string.
Example 1:
Input: "hello"
Output: "holle"
Example 2:
Input: "leetcode"
Output: "leotcede"
hint:
Vowels do not contain the letter "y".
Source: LeetCode
Link: https://leetcode-cn.com/problems/reverse-vowels-of-a-string
The copyright belongs to Lingkou Network. For commercial reprints, please contact the official authorization. For non-commercial reprints, please indicate the source.
Program:
/*
* @lc app=leetcode.cn id=345 lang=javascript
*
* [345] 反转字符串中的元音字母
*/
// @lc code=start
/**
* @param {string} s
* @return {string}
*/
var reverseVowels = function(s) {
let p1 = 0,
p2 = s.length -1,
strArr = s.split('');
const reg = /[aeiou]/i;
while(p1 < p2) {
if(reg.test(strArr[p1]) && reg.test(strArr[p2])) {
[strArr[p1],strArr[p2]] = [strArr[p2],strArr[p1]]
p1++;
p2--;
} else if(!reg.test(strArr[p1])) {
p1++;
} else if(!reg.test(strArr[p2])) {
p2--;
}
}
return strArr.join('');
};
The idea is relatively clear, that is, the first and last double pointers are traversed and replaced
2020.09.03
No.541 Reverse string-ii
Given a string s and an integer k, you need to reverse the first k characters every 2k characters from the beginning of the string.
If the remaining characters are less than k, then all the remaining characters are reversed.
If the remaining characters are less than 2k but greater than or equal to k, the first k characters are reversed and the remaining characters remain as they are.
Example:
Input: s = "abcdefg", k = 2
Output: "bacdfeg"
hint:
The string contains only lowercase English letters.
The length of the given string and k are in the range [1, 10000].
Source: LeetCode
Link: https://leetcode-cn.com/problems/reverse-string-ii
The copyright belongs to Lingkou Network. For commercial reprints, please contact the official authorization. For non-commercial reprints, please indicate the source.
Option One:
/*
* @lc app=leetcode.cn id=541 lang=javascript
*
* [541] 反转字符串 II
*/
// @lc code=start
/**
* @param {string} s
* @param {number} k
* @return {string}
*/
var reverseStr = function(s, k) {
let sArr = s.split(''),
arrs = [];
if(sArr.length < k){
arrs.push(sArr.reverse().join(''));
} else {
while(sArr.length >= k) {
let arr = sArr.splice(0, 2*k);
arrs.push(arr);
}
sArr.length > 0 && (arrs = [...arrs,sArr]);
for(let i =0; i< arrs.length; i++) {
// 在这里对arrs[i]的每项进行前k项调换
arrs[i] = arrs[i].splice(0, k).reverse().concat(arrs[i]).join('');
}
}
sArr=[...arrs];
return sArr.join('');
};
Option II:
/*
* @lc app=leetcode.cn id=541 lang=javascript
*
* [541] 反转字符串 II
*/
// @lc code=start
/**
* @param {string} s
* @param {number} k
* @return {string}
*/
var reverseStr = function(s, k) {
let strArr = s.split('');
let reverse = (start, end) => {
let temp = null;
while (start < end) {
temp = strArr[start];
strArr[start] = strArr[end];
strArr[end] = temp;
start++;
end--;
}
};
for (let i = 0; i < s.length; i += 2 * k) {
reverse(i, i + k - 1);
}
return strArr.join('');
};
There are two main ideas: one is to split 2k and then operate on k; the other is to search for mathematical laws and perform asynchronous operations on slicing.
2020.09.04
No.557 Reverse character string
Given a string, you need to reverse the character order of each word in the string, while still preserving the initial order of spaces and words.
Example:
Input: "Let's take LeetCode contest"
Output: "s'teL ekat edoCteeL tsetnoc"
hint:
In the string, each word is separated by a single space, and there will not be any extra spaces in the string.
Source: LeetCode
Link: https://leetcode-cn.com/problems/reverse-words-in-a-string-iii
The copyright belongs to Lingkou Network. For commercial reprints, please contact the official authorization. For non-commercial reprints, please indicate the source.
Option One:
/*
* @lc app=leetcode.cn id=557 lang=javascript
*
* [557] 反转字符串中的单词 III
*/
// @lc code=start
/**
* @param {string} s
* @return {string}
*/
var reverseWords = function(s) {
return s.split(' ').map(item => item.split('').reverse().join('')).join(' ');
};
Option II:
/*
* @lc app=leetcode.cn id=557 lang=javascript
*
* [557] 反转字符串中的单词 III
*/
// @lc code=start
/**
* @param {string} s
* @return {string}
*/
var reverseWords = function(s) {
const ret = [];
const length = s.length;
let i = 0;
while (i < length) {
let start = i;
while (i < length && s.charAt(i) != ' ') {
i++;
}
for (let p = start; p < i; p++) {
ret.push(s.charAt(start + i - 1 - p));
}
while (i < length && s.charAt(i) == ' ') {
i++;
ret.push(' ');
}
}
return ret.join('');
};
There are two solutions: 1. Use its own reverse and split api; 2. Use double pointers or loop traversal to split and reverse after matching;
2020.09.07
No.926 Flip the string to monotonically increasing
If a string composed of '0' and '1' is composed of some '0' (maybe no '0') followed by some '1' (or maybe no '1'), then the character The string is monotonically increasing.
We give a string S composed of characters '0' and '1', we can flip any '0' to '1' or flip '1' to '0'.
Returns the minimum number of flips that causes S to increase monotonically.
Example 1:
Input: "00110"
Output: 1
Explanation: We flip the last digit to get 00111.
Example 2:
Input: "010110"
Output: 2
Explanation: We flip it to get 011111, or 000111.
Example 3:
Input: "00011000"
Output: 2
Explanation: We flip to get 00000000.
hint:
1 <= S.length <= 20000
S contains only the characters '0' and '1'
Source: LeetCode
Link: https://leetcode-cn.com/problems/flip-string-to-monotone-increasing
The copyright belongs to Lingkou Network. For commercial reprints, please contact the official authorization. For non-commercial reprints, please indicate the source.
Option One:
/*
* @lc app=leetcode.cn id=926 lang=javascript
*
* [926] 将字符串翻转到单调递增
*/
// @lc code=start
/**
* @param {string} S
* @return {number}
*/
var minFlipsMonoIncr = function(S) {
let left = [],
right = [],
n = 0;
// 从左向右遍历,记录到字符串这个位置含有1的个数,全1数为left[S.length-1]的值
for( let i = 0; i < S.length; i++) {
if(S[i] == '1') n++;
left[i] = n;
}
// 从右向左遍历,记录到字符串这个位置含有0的个数,全0数为right[0]的值
n = 0; // 重置
for(let i = S.length -1; i >= 0;i--) {
if(S[i] == '0') n++;
right[i] = n;
}
// 移动窗口,选出到i位置包含0和1个数的和的最小值,即左边0右边1的最小值
n = Infinity;
for(let i = 0;i< S.length-1; i++) {
n = Math.min(left[i]+right[i+1],n);
}
// 返回 左边0右边1 全0 全1 三者的最小值
return Math.min(n, left[S.length-1], right[0])
};
Option II:
/*
* @lc app=leetcode.cn id=926 lang=javascript
*
* [926] 将字符串翻转到单调递增
*/
// @lc code=start
/**
* @param {string} S
* @return {number}
*/
const { min } = Math;
var minFlipsMonoIncr = function(S) {
let dp = Array.from({ length: S.length + 1 }).map(item => [0, 0]);
dp[0][0] = dp[0][1] = 0;
for (let i = 1; i <= S.length; i++) {
if (S[i - 1] === '0') {
dp[i][0] = dp[i - 1][0];
dp[i][1] = min(dp[i - 1][0], dp[i - 1][1]) + 1;
} else {
dp[i][0] = dp[i - 1][0] + 1;
dp[i][1] = min(dp[i - 1][0], dp[i - 1][1]);
}
}
return min(dp[S.length][0], dp[S.length][1]);
};
There are two solutions: 1. Use the idea of traversing the left and right pointers to the middle to maintain a data structure array. This data structure array stores arr=[location (the number stored in the location is 0 or 1)], and use this data The structure obtains the minimum value of all 0s, all 1s, left 0, right 1; 2. Dynamic programming, maintains a two-dimensional array, and performs state transition;
Summarize:
- The common idea of reversing the string type is to use the left and right pointers to move closer to the middle to perform the corresponding reversal. The middle may be the midpoint or other positions;
- You can use the existing related api to operate, the common ones are reverse, split, slice, etc. to perform string operations
Palindrome
2020.09.08
No.336 Palindromic Pair
Given a group of different words, find all the different index pairs (i, j), so that the two words in the list, words[i] + words[j], can be spliced into a palindrome.
Example 1:
Input: ["abcd","dcba","lls","s","sssll"]
Output: [[0,1],[1,0],[3,2],[2,4]]
Explanation: The palindrome that can be spliced into is ["dcbaabcd","abcddcba","slls","llssssll"]
Example 2:
Input: ["bat","tab","cat"]
Output: [[0,1],[1,0]]
Explanation: The palindrome that can be spliced into is ["battab","tabbat"]
Source: LeetCode
Link: https://leetcode-cn.com/problems/palindrome-pairs
The copyright belongs to Lingkou Network. For commercial reprints, please contact the official authorization. For non-commercial reprints, please indicate the source.
Option One:
/*
* @lc app=leetcode.cn id=336 lang=javascript
*
* [336] 回文对
*/
// @lc code=start
/**
* @param {string[]} words
* @return {number[][]}
*/
var palindromePairs = function(words) {
let r=[];
// 优化这里存储的数据结构,这里的存储是O(words.length^2*拼接后单词的长度)
for(let i = 0;i < words.length; i++) {
for(let j = i+1; j < words.length; j++) {
isReverse(words[i] + words[j]) && r.push([i,j]);
isReverse(words[j] + words[i]) && r.push([j,i]);
}
}
function isReverse(s) {
let p1 = 0,
p2 = s.length - 1;
while(p1 < p2) {
if( s[p1] != s[p2] ) return false;
p1++;
p2--;
}
return true;
}
return r;
};
Option II:
/*
* @lc app=leetcode.cn id=336 lang=javascript
*
* [336] 回文对
*/
// @lc code=start
/**
* @param {string[]} words
* @return {number[][]}
*/
var palindromePairs = function(words) {
//创建字典树中的节点对象
function createNode() {
var obj = {};
obj.chi = new Array(26).fill(0);
obj.flag = -1;
return obj;
};
var tree = new Array();
tree.push(createNode());
var n = words.length;
for(let i = 0; i < n; i++) {
insert(words[i], i); //将字符串数组中的所有字符串先加入字典树
};
var ret = new Array();
for(let i = 0; i < n; i++) {
var m = words[i].length;
for(let j = 0; j <= m; j++) {
if(isPalindrome(words[i], j, m - 1)) { //如果字符串i的j至m-1位为回文串
var leftId = findWord(words[i], 0, j - 1); //需要在字典树中寻找是否存在字符串i倒序的字符串
if (leftId != -1 && leftId != i) {
ret.push([i, leftId]);
}
}
if(j !=0 && isPalindrome(words[i], 0, j - 1)) {
var rightId = findWord(words[i], j, m - 1);
if(rightId != -1 && rightId != i) {
ret.push([rightId, i]);
}
}
}
};
return ret;
//将每一个字符串插入到字典树当中
function insert(s, id) {
var len = s.length, add = 0;
for(let i = 0; i < len; i++) {
var x = s[i].charCodeAt() - 'a'.charCodeAt();
if(tree[add].chi[x] == 0) {
tree.push(createNode());
tree[add].chi[x] = tree.length - 1;
}
//tree[add].ch[x]保存着子节点在tree中的位置;同时,不等于0说明当前字母与节点所代表的字母相等
add = tree[add].chi[x];
}
tree[add].flag = id; //标记下标为add的节点保存了第id个字符串
}
//判断字符串是否为回文
function isPalindrome(s, left, right) {
var len = right - left + 1;
for(let i = 0; i < len / 2; i++) {
if(s[left + i] != s[right - i]) {
return false;
}
}
return true;
}
//在字典树中寻找判断是否存在某字符串的倒序
function findWord(s, left, right) {
var add = 0;
for(let i = right; i >= left; i--) {
var x = s[i].charCodeAt() - 'a'.charCodeAt();
if(tree[add].chi[x] == 0) {
return -1;
}
add = tree[add].chi[x];
}
return tree[add].flag; //节点的flag在insert函数中保存了字符串在字符串数组中的下标
}
};
third solution:
/*
* @lc app=leetcode.cn id=336 lang=javascript
*
* [336] 回文对
*/
// @lc code=start
/**
* @param {string[]} words
* @return {number[][]}
*/
var palindromePairs = function (words) {
let n = words.length,
_result = [],
map = new Map()
for (let i = 0; i < n; ++i) {
// 生成倒序字符字符map
const str = words[i].split('').reverse().join('')
map.set(str, i)
}
for (let i = 0; i < n; i++) {
let word = words[i],
m = words[i].length
if (m == 0) continue
for (let j = 0; j <= m; j++) {
// 前缀片段为回文,则验证后缀片段是否存在与之匹配的回文
if (check(word, j, m - 1)) {
let leftId = findWord(word, 0, j - 1)
if (leftId !== -1 && leftId !== i) {
_result.push([i, leftId])
}
}
// 同理,后缀片段为回文,则验证前缀片段是否可以匹配到回文
if (j !== 0 && check(word, 0, j - 1)) {
let rightId = findWord(word, j, m - 1)
if (rightId !== -1 && rightId !== i) {
_result.push([rightId, i])
}
}
}
}
function check(s, left, right) {
let len = right - left + 1
for (let i = 0; i < len / 2; i++) {
if (s.charAt(left + i) !== s.charAt(right - i)) {
return false
}
}
return true
}
function findWord(s, left, right) {
return map.has(s.substring(left, right + 1))
? map.get(s.substring(left, right + 1))
: -1
}
return _result
}
There are three solutions: 1. Violent solution: loop through the matching of the string array to determine whether the palindrome is correct, and then output it, which is easy to think, but the time and space complexity is too bad; 2. The dictionary tree is optimized for the data structure of the storage structure. ; 3. Prefix + suffix or call center interception judgment, use the characteristics of palindrome characters to split the palindrome center, and then judge the output
2020.09.09
No.564 Find the number of the nearest palindrome
Given an integer n, you need to find the number of palindromes closest to it (not including itself).
"Nearest" is defined as the smallest absolute value of the difference between two integers.
Example 1:
Input: "123"
Output: "121"
Notice:
n is a positive integer represented by a character string, and its length does not exceed 18.
If there are multiple results, return the smallest one.
Source: LeetCode
Link: https://leetcode-cn.com/problems/find-the-closest-palindrome
The copyright belongs to Lingkou Network. For commercial reprints, please contact the official authorization. For non-commercial reprints, please indicate the source.
Option One:
/*
* @lc app=leetcode.cn id=564 lang=javascript
*
* [564] 寻找最近的回文数
*/
// @lc code=start
/**
* @param {string} n
* @return {string}
*/
var nearestPalindromic = function(n) {
let r = [],
len = n.length,
min = '',
c = 13; // 截取中间的位数
if(len < c) {
let [r1, r2] = getR(n);
getMin(r1,r2,n)
return min;
} else {
let m = reverse(n,len-c).slice(len-c,c),
l = reverse(n,len-c).slice(0,len-c),
r = reverse(n,len-c).slice(c,len);
let [r1, r2] = getR(m);
getMin(r1,r2,m);
return l+min+r;
}
// 获取最小值,也是最终返回的结果
function getMin(r1,r2,n) {
if(Math.abs(r1-n) < Math.abs(r2-n)) {
min= r1;
} else if(Math.abs(r1-n) == Math.abs(r2-n)) {
min= Math.min(r1,r2)+''
} else {
min= r2;
}
}
// 获取距离n最近的两个回文数的数组r
function getR(n) {
// 寻找第一个不是0的数
let str = ( n[0] == '0' ? n.slice(1,n.length-1) : n );
str = Number(str);
for(let i=1;; i++) {
if(isReverse(str+i)){
r.push(`${str+i}`);
}
if(isReverse(str-i)) {
r.push(`${str-i}`);
};
if(r.length >= 2) break;
}
r = r.map(i=>n[0] == '0' ? i = '0' + i + '0' : i)
return r;
}
// 判断是否是回文数
function isReverse(s) {
s += '';
let l = 0,
r = s.length - 1;
while(l<r) {
if(s[l] != s[r]) return false;
l++;
r--;
}
return true;
}
// 反转回文数
function reverse(s,l) {
s += '';
let p1 = 0,
p2 = len -1,
arr=s.split('');
for(let i=0;i<l;i++) {
if(arr[p1+i] != arr[p2-i]) arr[p2-i] = arr[p1+i];
}
return arr.join('');
}
};
Option II:
/*
* @lc app=leetcode.cn id=564 lang=javascript
*
* [564] 寻找最近的回文数
*/
// @lc code=start
/**
* @param {string} n
* @return {string}
*/
var nearestPalindromic = function (n) {
let palindromicList = ["",""] //初始化数组,用于存放 小于n的最近回文数 和 大于n的最近回文数
let nearest = "" //最近回文数
let lenN = n.length
let halfN = ""
let typeN = false //不是回文数
if (Number(n) < 11) { //个位数需要单独处理
nearest = String(Number(n) - 1)
return nearest
} else if (Number(n) == 11) {
nearest = "9"
return nearest
}
if (n.split("").reverse().join("") == n) {
typeN = true //n本身就是回文数
}
let isEvenNum = lenN % 2 == 0 //n是否为偶数
if (isEvenNum) { //长度为偶数位,则截取 [0,lenN/2) 的元素
halfN = n.slice(0, lenN / 2)
} else { //长度为奇数位,则截取 [0,Math.ceil(lenN/2))的元素
halfN = n.slice(0, Math.ceil(lenN / 2))
}
let lenHalfN = halfN.length
for (let L = Number(halfN) - 1, R = Number(halfN); L >= -1; L--, R++) { //halfN作为起始点 ,左右两边同时查找
let revsL = ""
let strL = Math.abs(L).toString()
let lenStrL = strL.length
if (isEvenNum) {
revsL = strL.split("").reverse().join("")
} else {
revsL = strL.substring(0, lenStrL - 1).split("").reverse().join("")
}
let palindromicL = strL + revsL.toString()
if (palindromicL.length < lenN) { //处理1000 > 999 等 字符串长度减少的情况,需要补1位
palindromicL += strL[0] //999 --> 9999
}
if (palindromicL != n) {
if ((Math.abs(palindromicL - n)) < (Math.abs(palindromicList[0] - n))) {
palindromicList[0] = palindromicL
}
}
let revsR = ""
let strR = R.toString()
let lenStrR = strR.length
if (isEvenNum) {
revsR = strR.split("").reverse().join("")
if (lenStrR > lenHalfN) {
revsR = revsR.substr(1)
}
} else {
revsR = strR.substring(0, lenStrR - 1).split("").reverse().join("")
if (revsR.length == 0) { //处理 个位数情况
revsR = strR
} else if (lenStrR > lenHalfN) { //处理 999 + 1 = 1000 等 字符串长度增加的情况,需要去掉1位
revsR = revsR.substr(1) // 0001 --> 001
}
}
let palindromicR = strR + String(revsR)
if ((Math.abs(palindromicR - n) < Math.abs(n - palindromicList[0]) && (palindromicR < n))) {
palindromicList[0] = palindromicR
continue
}
if (palindromicR != n) {
palindromicList[1] = palindromicR
break
}
}
if (palindromicList[1] - n < n - palindromicList[0]) {
nearest = palindromicList[1]
} else {
nearest = palindromicList[0]
}
return nearest
};
There are two solutions: 1. Violent solution: query the left and right range directly with the string as the center, and get the two nearest palindrome numbers. There is a maximum value in js, so certain operations need to be performed on the values when processing. This method is easier to think, but the time complexity is relatively large; 2. Analyze mathematical expressions, perform detailed processing on individual boundaries, and obtain the final result
2020.09.10
No.647 palindrome substring
Given a string, your task is to count how many palindrome substrings are in this string.
Substrings with different start positions or end positions, even if they consist of the same characters, will be regarded as different substrings.
Example 1:
Input: "abc"
Output: 3
Explanation: Three palindrome substrings: "a", "b", "c"
Example 2:
Input: "aaa"
Output: 6
Explanation: 6 palindrome substrings: "a", "a", "a", "aa", "aa", "aaa"
hint:
The length of the input string will not exceed 1000.
Source: LeetCode
Link: https://leetcode-cn.com/problems/palindromic-substrings
The copyright belongs to Lingkou Network. For commercial reprints, please contact the official authorization. For non-commercial reprints, please indicate the source.
Option One:
/*
* @lc app=leetcode.cn id=647 lang=javascript
*
* [647] 回文子串
*/
// @lc code=start
/**
* @param {string} s
* @return {number}
*/
var countSubstrings = function(s) {
let r = [],
len = s.length;
for(let i=1;i<=len;i++) {
getTemp(i).forEach(a => isReverse(a) && r.push(a))
}
return r.length;
// 移动窗口获取所有子串
function getTemp(n) {
let start = 0,
end = start + n,
temp = []; // 用于存放截取的子串
for(let i=0;i< len + 1 - n;i++,start++,end++) {
temp.push(s.slice(start,end))
}
return temp;
}
function isReverse(s) {
let p1=0,p2=s.length-1;
while(p1<p2) {
if(s[p1] != s[p2]) return false;
p1++;
p2--;
}
return true;
}
};
Option II:
/*
* @lc app=leetcode.cn id=647 lang=javascript
*
* [647] 回文子串
*/
// @lc code=start
/**
* @param {string} s
* @return {number}
*/
var countSubstrings = function(s) {
const n = s.length;
let ans = 0;
for (let i = 0; i < 2 * n - 1; ++i) {
let l = i / 2, r = i / 2 + i % 2;
while (l >= 0 && r < n && s.charAt(l) == s.charAt(r)) {
--l;
++r;
++ans;
}
}
return ans;
};
third solution:
/*
* @lc app=leetcode.cn id=647 lang=javascript
*
* [647] 回文子串
*/
// @lc code=start
/**
* @param {string} s
* @return {number}
*/
const countSubstrings = (s) => {
const len = s.length;
let count = 0;
const dp = new Array(len);
for (let j = 0; j < len; j++) {
for (let i = 0; i <= j; i++) {
if (s[i] == s[j] && (j - i <= 1 || dp[i + 1])) {
dp[i] = true;
count++;
} else {
dp[i] = false;
}
}
}
return count;
};
Option Four:
/*
* @lc app=leetcode.cn id=647 lang=javascript
*
* [647] 回文子串
*/
// @lc code=start
/**
* @param {string} s
* @return {number}
*/
var countSubstrings = function(s) {
let n = s.length;
let t = ['$', '#'];
for (let i = 0; i < n; ++i) {
t.push(s.charAt(i));
t.push('#');
}
n = t.length;
t.push('!');
t = t.join('');
const f = new Array(n);
let iMax = 0, rMax = 0, ans = 0;
for (let i = 1; i < n; ++i) {
// 初始化 f[i]
f[i] = i <= rMax ? Math.min(rMax - i + 1, f[2 * iMax - i]) : 1;
// 中心拓展
while (t.charAt(i + f[i]) == t.charAt(i - f[i])) {
++f[i];
}
// 动态维护 iMax 和 rMax
if (i + f[i] - 1 > rMax) {
iMax = i;
rMax = i + f[i] - 1;
}
// 统计答案, 当前贡献为 (f[i] - 1) / 2 上取整
ans += Math.floor(f[i] / 2);
}
return ans;
};
There are four solutions: 1. Violent solution: intercept the substring, get all the substrings, and then judge whether the palindrome substring is obtained, and then obtain the total number. At this time, the time complexity is O(n^3); 2. The central expansion: Based on the optimization of the brute force solution, the substring obtained here can be obtained by traversing the possible search center, and then the center is expanded to both sides to obtain the total number. At this time, the time complexity is O(n^2); 3. Dynamic programming: the string Dash, perform a combination match for each character, convert each dp[i] and dp[i-1], distinguish between 1 character and 2 characters and the combination of more than 2 characters, and the time complexity is O (n^2), the space complexity can be optimized to O(n); 4. Manacher: Use blanking to convert both odd and even strings into odd strings, so that there is only one center, and then proceed with different radii Center expansion, using the largest substring coverage radius to expand, so that the time to query the center can be optimized without blind traversal, and the time complexity is O(n)
2020.09.11
No.680 Verification of palindrome string-ii
Given a non-empty string s, delete at most one character. Determine whether it can become a palindrome string.
Example 1:
Input: "aba"
Output: True
Example 2:
Input: "abca"
Output: True
Explanation: You can delete the c character.
Notice:
The string only contains lowercase letters from az. The maximum length of the string is 50000.
Source: LeetCode
Link: https://leetcode-cn.com/problems/valid-palindrome-ii
The copyright belongs to Lingkou Network. For commercial reprints, please contact the official authorization. For non-commercial reprints, please indicate the source.
Option One:
/*
* @lc app=leetcode.cn id=680 lang=javascript
*
* [680] 验证回文字符串 Ⅱ
*/
// @lc code=start
/**
* @param {string} s
* @return {boolean}
*/
var validPalindrome = function(s) {
let n = 0; // 闭包应用,记录一个位置
if(!isReverse(s)) {
let arr1 = s.split(''),
arr2 = s.split('');
arr1.splice(n,1);
arr2.splice(s.length - 1 - n,1);
return (isReverse(arr1.join('')) || isReverse(arr2.join('')));
}
return true;
function isReverse(s) {
let p1 = 0,
p2 = s.length - 1;
while(p1 < p2) {
if(s[p1] != s[p2]) return false;
n++;
p1++;
p2--;
};
return true;
}
};
Mainly use the head and tail pointers to find the middle close, this topic is to verify the variant of palindrome string
Summarize:
- The palindrome scheme is mainly the dual-pointer search scheme. The search scheme here can be optimized, such as prefix suffix method, center expansion method, Manacher, etc.;
- For the scheme of generating palindrome strings from strings constructed by yourself, dynamic programming and general formulas of mathematical expressions can be used.
Longest problem
2020.09.14
No.3 The longest substring without repeated characters
Given a string, please find out the length of the longest substring that does not contain repeated characters.
Example 1:
Input: "abcabcbb"
Output: 3
Explanation: Because the longest substring without repeated characters is "abc", its length is 3.
Example 2:
Input: "bbbbb"
Output: 1
Explanation: Because the longest substring without repeated characters is "b", its length is 1.
Example 3:
Input: "pwwkew"
Output: 3
Explanation: Because the longest substring without repeated characters is "wke", its length is 3.
Please note that your answer must be the length of the substring, "pwke" is a subsequence, not a substring.
Source: LeetCode
Link: https://leetcode-cn.com/problems/longest-substring-without-repeating-characters
The copyright belongs to Lingkou Network. For commercial reprints, please contact the official authorization. For non-commercial reprints, please indicate the source.
Option One:
/*
* @lc app=leetcode.cn id=3 lang=javascript
*
* [3] 无重复字符的最长子串
*/
// @lc code=start
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let max = 0, index = 0;
for(let i=0,j=0;j<s.length;j++) {
index = s.slice(i,j).indexOf(s[j]);
if(isRepeat(s.slice(i,j))) {
i += index + 1;
}
max = Math.max(max, j - i + 1)
}
return max;
function isRepeat(s) {
return s.length == Array.from(new Set(s.split(''))).length;
}
};
Option II:
/*
* @lc app=leetcode.cn id=3 lang=javascript
*
* [3] 无重复字符的最长子串
*/
// @lc code=start
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let arr = [], max = 0
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.charAt(i))
max = Math.max(arr.length, max)
}
return max
};
third solution:
/*
* @lc app=leetcode.cn id=3 lang=javascript
*
* [3] 无重复字符的最长子串
*/
// @lc code=start
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let map = new Map(), max = 0
for(let i = 0, j = 0; j < s.length; j++) {
if(map.has(s[j])) {
i = Math.max(map.get(s[j]) + 1, i)
}
max = Math.max(max, j - i + 1)
map.set(s[j], j)
}
return max
};
Mainly use the sliding window for string selection and matching, here you can use string, array and map to do data structure search
2020.09.15
No.14 Longest common prefix
Write a function to find the longest common prefix in an array of strings.
If there is no common prefix, an empty string "" is returned.
Example 1:
Input: ["flower","flow","flight"]
Output: "fl"
Example 2:
Input: ["dog","racecar","car"]
Output: ""
Explanation: There is no common prefix for the input.
instruction:
All entries contain only lowercase letters az.
Source: LeetCode
Link: https://leetcode-cn.com/problems/longest-common-prefix
The copyright belongs to Lingkou Network. For commercial reprints, please contact the official authorization. For non-commercial reprints, please indicate the source.
Option One:
/*
* @lc app=leetcode.cn id=14 lang=javascript
*
* [14] 最长公共前缀
*/
// @lc code=start
/**
* @param {string[]} strs
* @return {string}
*/
var longestCommonPrefix = function(strs) {
if(strs.length == 0) return '';
let r = strs[0];
strs.forEach(str => {
r = commonStr(r,str)
});
return r;
function commonStr(str1, str2) {
let len = Math.min(str1.length, str2.length),
str = '';
for(let i=0; i<len; i++) {
if(str1[i] == str2[i]){
str += str1[i];
} else {
return str; // 有不同的不再往后比较
}
}
return str;
}
};
Option II:
/*
* @lc app=leetcode.cn id=14 lang=javascript
*
* [14] 最长公共前缀
*/
// @lc code=start
/**
* @param {string[]} strs
* @return {string}
*/
const longestCommonPrefix = (strs) => {
if (!strs || strs.length === 0) return ''
let lcp = '' // 共同的前缀字符串
let index = 0 // 指针
for (const c of strs[0]) { // 遍历第一个字符串的每个字符
for (let i = 1; i < strs.length; i++) { // 遍历剩余的字符串们
if (index >= strs[i].length || strs[i][index] !== c) {
return lcp
}
}
lcp += c
index++
}
return lcp
}
third solution:
/*
* @lc app=leetcode.cn id=14 lang=javascript
*
* [14] 最长公共前缀
*/
// @lc code=start
/**
* @param {string[]} strs
* @return {string}
*/
var longestCommonPrefix = function(strs) {
if(!strs || strs.length == 0){
return '';
}
strs.sort();
let first = strs[0];
let end = strs[strs.length-1];
// 此处 end.match(eval('/^'+first+'/')) 可以换成
// end.indexOf(first) == 0,是一样的
if(first == end || end.match(eval('/^'+first+'/'))){
return first;
}
for(let i = 0;i < first.length;i++){
if(first[i] != end[i]){
return first.substring(0,i);
}
}
};
Option Four:
/*
* @lc app=leetcode.cn id=14 lang=javascript
*
* [14] 最长公共前缀
*/
// @lc code=start
/**
* @param {string[]} strs
* @return {string}
*/
var longestCommonPrefix = function(strs) {
if (strs === null || strs.length === 0) return "";
return lCPrefixRec(strs)
};
// 若分裂后的两个数组长度不为 1,则继续分裂
// 直到分裂后的数组长度都为 1,
// 然后比较获取最长公共前缀
function lCPrefixRec(arr) {
let length = arr.length
if(length === 1) {
return arr[0]
}
let mid = Math.floor(length / 2),
left = arr.slice(0, mid),
right = arr.slice(mid, length)
return lCPrefixTwo(lCPrefixRec(left), lCPrefixRec(right))
}
// 求 str1 与 str2 的最长公共前缀
function lCPrefixTwo(str1, str2) {
let j = 0
for(; j < str1.length && j < str2.length; j++) {
if(str1.charAt(j) !== str2.charAt(j)) {
break
}
}
return str1.substring(0, j)
}
Option five:
/*
* @lc app=leetcode.cn id=14 lang=javascript
*
* [14] 最长公共前缀
*/
// @lc code=start
/**
* @param {string[]} strs
* @return {string}
*/
var longestCommonPrefix = function(strs) {
if (strs === null || strs.length === 0) return "";
// 初始化 Trie 树
let trie = new Trie()
// 构建 Trie 树
for(let i = 0; i < strs.length; i++) {
if(!trie.insert(strs[i])) return ""
}
// 返回最长公共前缀
return trie.searchLongestPrefix()
};
// Trie 树
var Trie = function() {
this.root = new TrieNode()
};
var TrieNode = function() {
// next 放入当前节点的子节点
this.next = {};
// 当前是否是结束节点
this.isEnd = false;
};
Trie.prototype.insert = function(word) {
if (!word) return false
let node = this.root
for (let i = 0; i < word.length; i++) {
if (!node.next[word[i]]) {
node.next[word[i]] = new TrieNode()
}
node = node.next[word[i]]
}
node.isEnd = true
return true
};
Trie.prototype.searchLongestPrefix = function() {
let node = this.root
let prevs = ''
while(node.next) {
let keys = Object.keys(node.next)
if(keys.length !== 1) break
if(node.next[keys[0]].isEnd) {
prevs += keys[0]
break
}
prevs += keys[0]
node = node.next[keys[0]]
}
return prevs
}
There are many ways to solve this problem, and there are mainly five common ones: 1. Horizontal comparison, get the string, compare two adjacent ones with each other to get the smallest substring; 2. Vertical comparison, maintain a pointer, and perform the same position of all strings Vertical comparison; 3. Sort by character first, only need to compare the first and last positions of each character, and finally receive a string, which is regarded as an optimization of vertical comparison; 4. Divide and conquer algorithm, use divide and conquer to compare two The two comparisons are grouped to optimize the comparison time; 5. Trie tree, maintain a Trie tree, and output the longest common prefix
2020.09.16
No.32 The longest valid parenthesis
Given a string containing only'(' and')', find the length of the longest substring containing valid parentheses.
Example 1:
Input: "(()"
Output: 2
Explanation: The longest valid bracket substring is "()"
Example 2:
Input: ")()())"
Output: 4
Explanation: The longest valid bracket substring is "()()"
Source: LeetCode
Link: https://leetcode-cn.com/problems/longest-valid-parentheses
The copyright belongs to Lingkou Network. For commercial reprints, please contact the official authorization. For non-commercial reprints, please indicate the source.
Option One:
/*
* @lc app=leetcode.cn id=32 lang=javascript
*
* [32] 最长有效括号
*/
// @lc code=start
/**
* @param {string} s
* @return {number}
*/
var longestValidParentheses = function(s) {
let left = [],
right = [],
r = []; // 将可以匹配的位置收到一个数组中
// 遍历,将'('和')'的位置分别记录在left数组和right数组中
for(let i = 0; i < s.length; i++) {
if(s[i] == '(') {
left.push(i);
} else if(s[i] == ')') {
right.push(i)
}
}
// 对left数组中的位置和right数组中的位置进行临近的配对,配对要求右边数组的值要比左边数组的值大
for(let i=left.length-1; i>=0; i--) {
for(let j=0; j<right.length; j++) {
if(left[i] < right[j]) {
r.push(left[i],right[j]);
left.splice(i,1);
right.splice(j,1);
continue;
}
}
};
r.sort((a,b)=>a-b);
// 获取r中最长连续数字
let pos = [],
max = 0;
for(let i=0;i<=r.length-1;i++) {
if(r[i+1] - r[i] != 1) {
pos.push(i+1)
}
}
pos.unshift(0);
// 分割位置数组的gap进行最大值获取,取得的最大值就是最长有效括号
for(let i=0;i<pos.length-1;i++) {
if(max < pos[i+1] - pos[i]) max = pos[i+1] - pos[i];
}
return max;
};
Option II:
/*
* @lc app=leetcode.cn id=32 lang=javascript
*
* [32] 最长有效括号
*/
// @lc code=start
/**
* @param {string} s
* @return {number}
*/
var longestValidParentheses = function (s) {
const stack = [-1]
let ans = 0
for (let i = 0; i < s.length; i++) {
if (s[i] === '(') {
stack.push(i)
} else {
stack.pop()
if (stack.length === 0) {
// 加入新边界
stack.push(i)
} else {
ans = Math.max(ans, i - stack[stack.length - 1])
}
}
}
return ans
}
third solution:
/*
* @lc app=leetcode.cn id=32 lang=javascript
*
* [32] 最长有效括号
*/
// @lc code=start
/**
* @param {string} s
* @return {number}
*/
var longestValidParentheses = function(s) {
let len = s.length,
_result = 0;
if (len === 0) return _result
let dp = Array(len).fill(0);
for (let i = 1; i < s.length; i++) {
if (s.charAt(i) == ')') {
if (s.charAt(i - 1) == '(') {
dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
}
else if (
i - dp[i - 1] > 0 &&
s.charAt(i - dp[i - 1] - 1) == '('
) {
dp[i] = dp[i - 1] +
((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0)
+ 2;
}
_result = Math.max(_result, dp[i]);
}
}
return _result
};
Option Four:
/*
* @lc app=leetcode.cn id=32 lang=javascript
*
* [32] 最长有效括号
*/
// @lc code=start
/**
* @param {string} s
* @return {number}
*/
var longestValidParentheses = function(s) {
let temp = s,
reg = new RegExp(/(\((1*)\))/ig);
while(reg.test(temp)){
temp = temp.replace(reg,1+'$2');
}
let arr = temp.split(/[\(\)]/ig);
return arr.reduce((total,item,index)=>{
let len = item.length*2;
total = total > len ? total : len;
return total;
},0)
};
There are many ways to solve this problem, and there are mainly 4 methods: 1. Use the position of the left and right brackets to pair and output the maximum value; 2. Use the stack entry and exit to calculate the value of the matching process in 1; 3. Dynamic programming, find the general term formula Perform matching; 4. Regular replacement, replace the matching ones, and get the corresponding number
2020.09.17
No.521 Longest Special Sequence I
Here are two strings, please find the longest special sequence from these two strings.
The "longest special sequence" is defined as follows: the sequence is the longest subsequence unique to a string (that is, it cannot be a subsequence of other strings).
The subsequence can be achieved by deleting some characters in the string, but the relative order of the remaining characters cannot be changed. An empty sequence is a subsequence of all strings, and any string is a subsequence of itself.
The input is two strings, and the length of the longest special sequence is output. If it does not exist, it returns -1.
Example 1:
Input: "aba", "cdc"
Output: 3
Explanation: The longest special sequence can be "aba" (or "cdc"), both of which are their own subsequences and not the other's subsequences.
Example 2:
Input: a = "aaa", b = "bbb"
Output: 3
Example 3:
Input: a = "aaa", b = "aaa"
Output: -1
hint:
Both strings are in the range [1-100].
The characters in the string only contain'a'~'z'.
Source: LeetCode
Link: https://leetcode-cn.com/problems/longest-uncommon-subsequence-i
The copyright belongs to Lingkou Network. For commercial reprints, please contact the official authorization. For non-commercial reprints, please indicate the source.
Program:
/*
* @lc app=leetcode.cn id=521 lang=javascript
*
* [521] 最长特殊序列 Ⅰ
*/
// @lc code=start
/**
* @param {string} a
* @param {string} b
* @return {number}
*/
var findLUSlength = function(a, b) {
if(a == b) {
return -1;
} else {
return Math.max(a.length, b.length);
}
};
The word game is actually testing whether the two strings are the same
2020.09.18
No.521 Longest Special Sequence II
Given a list of strings, you need to find the longest special sequence from them. The longest special sequence is defined as follows: the sequence is the longest subsequence unique to a string (that is, it cannot be a subsequence of other strings).
The subsequence can be achieved by deleting some characters in the string, but the relative order of the remaining characters cannot be changed. An empty sequence is a subsequence of all strings, and any string is a subsequence of itself.
The input will be a list of strings, and the output will be the length of the longest special sequence. If the longest special sequence does not exist, -1 is returned.
Example:
Input: "aba", "cdc", "eae"
Output: 3
hint:
The length of all given strings will not exceed 10.
The length of the given string list will be between [2, 50].
Source: LeetCode
Link: https://leetcode-cn.com/problems/longest-uncommon-subsequence-ii
The copyright belongs to Lingkou Network. For commercial reprints, please contact the official authorization. For non-commercial reprints, please indicate the source.
Program:
/*
* @lc app=leetcode.cn id=522 lang=javascript
*
* [522] 最长特殊序列 II
*/
// @lc code=start
/**
* @param {string[]} strs
* @return {number}
*/
var findLUSlength = function(strs) {
// 对数组进行排序,将字符串长度较大的排在前面
strs.sort((a,b) => b.length - a.length);
let maxStr = '', flag = true;
for(let i=0;i<strs.length;i++) {
maxStr = strs[i];
for(let j=0;j<strs.length;j++){
if(j!=i) {
if(strs[j].includes(maxStr)) {
flag = false;
break;
} else {
// 求子序列
if(isSubseq(strs[j],maxStr)) {
flag = false;
break;
} else {
flag = true;
}
}
}
}
if(flag) break;
}
if(flag) {
return maxStr.length;
} else {
return -1;
}
// 判断str2是否是str1的子序列
function isSubseq(str1,str2) {
let i = 0,
j = 0;
while ( i < str1.length && j < str2.length ) {
if (str2.charAt(j) == str1.charAt(i)) {
j++;
}
i++;
}
return j == str2.length;
}
};
Get the longest string, and then determine whether it is a subsequence, pay attention to whether it is a subsequence here, make a function to judge
Summarize:
- The longest solution is mainly designed to recursion and looping, where data structures such as stacks and trees can be used to optimize the structure to reduce the time;
- For the problem that needs to be constantly searched for the longest, you can consider general term formula solutions such as dynamic programming, divide-and-conquer algorithms, etc.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。