We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JavaScript实现LeetCode第5题:最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad" 输出: "bab"
注意: "aba" 也是一个有效答案。 示例 2:
输入: "cbbd" 输出: "bb"
从每个位置出发,向两边扩散即可。遇到不是回文的时候结束。举个例子,str = acdbbdaastr=acdbbdaa 我们需要寻找从第一个 b(位置为 33)出发最长回文串为多少。怎么寻找? 首先往左寻找与当前位置相同的字符,直到遇到不相等为止。 然后往右寻找与当前位置相同的字符,直到遇到不相等的为止。 最后左右双向扩散,直到左和右不相等。
每个位置向两边扩散都会出现一个窗口大小(len)。如果 len > maxLen(用来表示最长回文子串的长度)。则更新 maxLen的值。 最后要求返回的是具体子串,而不是长度,所以要记录 maxLen 的起始位置(maxStart),即此时还要 maxStart=left;
/** * @param {string} s * @return {string} */ var longestPalindrome = function(s) { if(!s) { return ''; } let strLen = s.length; // 从中间向左右两边遍历 let left = 0; let right = 0; // 遍历到当前的长度 let len = 1; // 用来表示最长回文串的长度 let maxLen = 0; // 最后要求返回的是具体子串,而不是长度,所以要记录 maxLen 的起始位置(maxStart) let maxStart = 0; for(let i = 0; i < strLen; i++) { left = i - 1; right = i + 1; while(left >= 0 && s[i] === s[left]) { len++; left --; } while(right < strLen && s[i] === s[right]) { len++; right++; } while(left >= 0 && right < strLen && s[left] === s[right]) { len+=2; left--; right++; } if(len > maxLen) { maxLen = len; maxStart = left; } len = 1; } // maxStart + 1而不是 maxStart ,是因为上传每次while循环后,left都会执行 -- 操作 return s.substring(maxStart + 1, maxStart + maxLen + 1); };
用 boolean dp[l][r] 表示从 l 到 r 这段是否为回文。试想如果 dp[l][r] = true,如果要判断 dp[l-1][r+1]是否为回文。只需要判断字符在 (l-1)和(r+1)两个位置是否为相同的字符,是不是减少了很多计算;
动态规划关键是找到初始状态和状态转移方程。 初始状态,l = r 时,此时 dp[l][r] = true 状态转移方程, dp[l][r] = true 并且 (l - 1)和 (r + 1)两个位置为相同的字符,此时 dp[l - 1][r + 1] = true;
/** * @param {string} s * @return {string} */ /** * @param {string} s * @return {string} */ var longestPalindrome = function(s) { if(!s || s.length < 2) { return s; } let strLen = s.length; // 最长回文串的起点 let maxStart = 0; // 最长回文串的终点 let maxEnd = 0; // 最长回文串的长度 let maxLen = 1; let dp = Array.from(new Array(strLen),() => new Array(strLen).fill(false)); for(let r = 1; r < strLen; r++) { for(let l = 0; l < r; l++) { // r-l <= 2 为了兼容 aa(r-l=1)和aba(r-l=2)这两种回文串 if(s[l] === s[r] && (r-l <= 2 || dp[l + 1][r - 1])) { dp[l][r] = true; // 如果 此时的长度 > maxLen, 则更新 maxLen的值。 if(r - l + 1 > maxLen) { maxLen = r - l + 1; maxStart = l; maxEnd = r; } } } } return s.substring(maxStart, maxEnd + 1); };
尝试了一下,花费的时间比第一个的中心拓展法要多,还待研究。
一个复杂度为 O(n) 的 Manacher 算法.
该算法暂时还没完全搞懂,可以去网上搜一下很多讲解。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
JavaScript实现LeetCode第5题:最长回文子串
题目描述
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
注意: "aba" 也是一个有效答案。
示例 2:
思路
1. 中心扩散法:
从每个位置出发,向两边扩散即可。遇到不是回文的时候结束。举个例子,str = acdbbdaastr=acdbbdaa 我们需要寻找从第一个 b(位置为 33)出发最长回文串为多少。怎么寻找?
首先往左寻找与当前位置相同的字符,直到遇到不相等为止。
然后往右寻找与当前位置相同的字符,直到遇到不相等的为止。
最后左右双向扩散,直到左和右不相等。
每个位置向两边扩散都会出现一个窗口大小(len)。如果 len > maxLen(用来表示最长回文子串的长度)。则更新 maxLen的值。
最后要求返回的是具体子串,而不是长度,所以要记录 maxLen 的起始位置(maxStart),即此时还要 maxStart=left;
2. 动态规划法
用 boolean dp[l][r] 表示从 l 到 r 这段是否为回文。试想如果 dp[l][r] = true,如果要判断 dp[l-1][r+1]是否为回文。只需要判断字符在 (l-1)和(r+1)两个位置是否为相同的字符,是不是减少了很多计算;
动态规划关键是找到初始状态和状态转移方程。
初始状态,l = r 时,此时 dp[l][r] = true
状态转移方程, dp[l][r] = true 并且 (l - 1)和 (r + 1)两个位置为相同的字符,此时 dp[l - 1][r + 1] = true;
尝试了一下,花费的时间比第一个的中心拓展法要多,还待研究。
Manacher(马拉车)算法
一个复杂度为 O(n) 的 Manacher 算法.
该算法暂时还没完全搞懂,可以去网上搜一下很多讲解。
参考
The text was updated successfully, but these errors were encountered: