pre: 作为一个菜鸡,笔试题一直是自己的噩梦,之前做了很多公司的笔试,一直太懒没有认真再做一遍,所以最近有空就编了一下回文子串的程序,不过依然是 n^2 的时间复杂度,就当作学习笔记好了。
1.中心扩散法
中心扩散法,最初是在论坛其他文章看到的,时隔很久之后,自己才真正写的,不过加入了 截取子串的长度和当前最长回文长度 的比较,会减少操作量。也写了记录运行时间的函数,可以在浏览器 console 查看。
function centerSpread(str) {
let date = new Date();
arrDuration.push(date.getTime());
var maxLength = 1;
let maxString = '';
// 中心向左右扩散,并比较子串长度和当前最长回文子串长度,减少时间复杂度
// 单核
for (let i = Math.ceil(str.length / 2); i > 0; i--) {
if (i * 2 < maxLength) {} else {
// 截取子串并判断
sub2(testStr, i, i);
}
}
for (let i = Math.ceil(str.length / 2); i < str.length - 2; i++) {
if ((str.length - i) * 2 < maxLength) {} else {
sub2(testStr, i, i);
}
}
//双核
for (let i = Math.ceil(str.length / 2); i < str.length - 2; i++) {
if ((str.length - i) * 2 > maxLength && testStr.charAt(i) == testStr.charAt(i + 1)) {
sub2(testStr, i, i + 1);
} else {}
}
for (let i = Math.ceil(str.length / 2); i > 0; i--) {
if ((i + 1) * 2 > maxLength && testStr.charAt(i) == testStr.charAt(i + 1)) {
sub2(testStr, i, i + 1);
} else {}
}
console.log("maxString - " + maxString);
console.log(testStr.indexOf(maxString));
// 双核 left != right 单核 left == right
function sub2(str, left, right) {
let dis = 1;
let subMaxLength = left == right ? 1 : 2;
while (str.charAt(left - dis) == str.charAt(right + dis)) {
subMaxLength += 2;
//console.log(subMaxLength + '-' + str.substring(left - dis, right + dis + 1));
if (subMaxLength > maxString.length) {
maxString = str.substring(left - dis, right + dis + 1);
}
dis++;
}
}
}
2.动态规划
很基础的动态规划,找出规律和初始条件(有种做数学题的感觉),然后构建规划矩阵,在这个规划中,通过子串长度和子串起点位置构建二维矩阵。并且后面发现 一个回文子串的子串中必然也有回文,可以减少很多操作量,就变成了优化的动态规划。(其实也说不上优化哈哈哈)
function dynamicProgram(testStr) {
let date = new Date();
arrDuration.push(date.getTime());
// matrix: 二维矩阵,记录回文长度数据
var matrix = new Array();
for (let i = 0; i < testStr.length - 1; i++) {
matrix[i] = [];
for (let j = 0; j < testStr.length - i - 1; j++) {
//matrix[i][j] = 0;
}
}
// i - 子串长度
// j - 起点位置
let maxString = '';
for (let i = 0; i < testStr.length - 1; i++) {
for (let j = 0; j < testStr.length - i - 1; j++) {
if (i == 0) {
matrix[i][j] = 1;
} else {
if (testStr.charAt(j) == testStr.charAt(i + j) && i == 1) {
matrix[i][j] = 2;
} else if (testStr.charAt(j) == testStr.charAt(i + j) && i > 1) {
matrix[i][j] = matrix[i - 2][j + 1] + 2;
if (maxString.length < matrix[i][j]) {
maxString = testStr.substring(j, i + j + 1)
}
} else {
// matrix[i][j] = 0;
}
}
}
}
// console.table(matrix);
console.log('maxString - ' + maxString);
console.log(testStr.indexOf(maxString));
}
3.简化的动态规划
function simplifyDynamicProgram(testStr) {
let date = new Date();
arrDuration.push(date.getTime());
var matrix = new Array();
for (let i = 0; i < testStr.length - 1; i++) {
matrix[i] = [];
for (let j = 0; j < testStr.length - i - 1; j++) {
//matrix[i][j] = 0;
}
}
// i - 子串长度
// j - 起点位置
let maxString = '';
// arraySubscript - 暂存 i j
// 利用 arraySubscript 来存储包含回文的小子串,简化计算量
let arraySubscript = [];
for (let i = 0; i < 3; i++) {
for (let j = 0; j < testStr.length - i - 1; j++) {
if (i == 0) {
matrix[i][j] = 1;
} else {
if (testStr.charAt(j) == testStr.charAt(i + j) && i == 1) {
matrix[i][j] = 2;
arraySubscript.push({
i,
j
});
} else if (testStr.charAt(j) == testStr.charAt(i + j) && i > 1 && matrix[i - 2][j + 1] > 0) {
matrix[i][j] = matrix[i - 2][j + 1] + 2;
arraySubscript.push({
i,
j
});
if (maxString.length < matrix[i][j]) {
maxString = testStr.substring(j, i + j + 1)
}
} else {
// matrix[i][j] = 0;
}
}
}
}
for (let k = 0; k < arraySubscript.length; k++) {
let i = arraySubscript[k].i + 2;
let j = arraySubscript[k].j - 1;
if (i + j < testStr.length && i > 0 && j > 0 && testStr.charAt(j) == testStr.charAt(i + j)) {
matrix[i][j] = i + 1;
arraySubscript.push({
i,
j
});
if (matrix[i][j] > maxString.length) {
maxString = testStr.substring(j, i + j + 1);
}
}
}
//console.table(matrix);
//console.table(arraySubscript);
console.log('maxString - ' + maxString);
console.log(testStr.indexOf(maxString));
}
4.完整代码
<!DOCTYPE html>
<html lang="en">
<!--
一、主要函数:
1. centerSpread(string): 中心扩散
2. dynamicProgram(string): 动态规划
3. simpilifyDynamicProgram(string): 优化后的动态规划
二、全局变量:
1. testStr: 测试字符串
2. arrDuration: 记录运行时间
-->
<head>
<meta charset="UTF-8">
<title>最长回文子串</title>
</head>
<body>
<script>
var testStr = 'abcaabacaaaaacabcabacabacbabaaaaaaabaaaaaaaabaaaaaaaaaaaaaaaab' +
'aaaaaaaabaaaaaaaaaaaabcaabacaaaaaaaaaaaaaaaaaacaabaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
'cbabcbcabcabcbaaaaaaaaaaaaaaacabaaaaaaaacbacbabcbabcbcabcbaacbabcbcabcabcbcabacb' +
'acbabcbabcbcabcbaacbabcbcabcbcbcabacbacbabcbabcbcabcbaabcaabacaaaaacabcabacabacba' +
'babcaabacaaaaacaabacbabcbcabcbcbcabacbacbabcbabcbcabcbaacbabcbcabcbcbcabacbacbabcb' +
'abcbcabcbaacbabcbcabcbcbcabacbacbabcbabcbcabcbaabcaabacaaaaacabcabacabacbababcaabac' +
'aaaaacaabacbabcbcabcbcbcabacbacbabcbabcbcabcbaacbabcbcabcbcbcabacbacbabcbabcbcabcbaac' +
'babcbcabcbcbcabacbacbabcbabcbcabcbaabcaabacaaaaacabcabacabacbababcaabacaaaaacaabacbabcbca' +
'bcbcbcabacbacbabcbabcbcabcbaacbabcbcabcbcbcabacbacbabcbabcbcabcbaacbabcbcabcbcbcabacbacbabcbabcbcabcba';
var arrDuration = [];
console.log('testStr.length - ' + testStr.length);
centerSpread(testStr);
dynamicProgram(testStr);
simplifyDynamicProgram(testStr);
final();
console.log(arrDuration);
function centerSpread(str) {
let date = new Date();
arrDuration.push(date.getTime());
var maxLength = 1;
let maxString = '';
// 中心向左右扩散,并比较子串长度和当前最长回文子串长度,减少时间复杂度
// 单核
for (let i = Math.ceil(str.length / 2); i > 0; i--) {
if (i * 2 < maxLength) {} else {
// 截取子串并判断
sub2(testStr, i, i);
}
}
for (let i = Math.ceil(str.length / 2); i < str.length - 2; i++) {
if ((str.length - i) * 2 < maxLength) {} else {
sub2(testStr, i, i);
}
}
//双核
for (let i = Math.ceil(str.length / 2); i < str.length - 2; i++) {
if ((str.length - i) * 2 > maxLength && testStr.charAt(i) == testStr.charAt(i + 1)) {
sub2(testStr, i, i + 1);
} else {}
}
for (let i = Math.ceil(str.length / 2); i > 0; i--) {
if ((i + 1) * 2 > maxLength && testStr.charAt(i) == testStr.charAt(i + 1)) {
sub2(testStr, i, i + 1);
} else {}
}
console.log("maxString - " + maxString);
console.log(testStr.indexOf(maxString));
// 双核 left != right 单核 left == right
function sub2(str, left, right) {
let dis = 1;
let subMaxLength = left == right ? 1 : 2;
while (str.charAt(left - dis) == str.charAt(right + dis)) {
subMaxLength += 2;
//console.log(subMaxLength + '-' + str.substring(left - dis, right + dis + 1));
if (subMaxLength > maxString.length) {
maxString = str.substring(left - dis, right + dis + 1);
}
dis++;
}
}
}
function dynamicProgram(testStr) {
let date = new Date();
arrDuration.push(date.getTime());
// matrix: 二维矩阵,记录回文长度数据
var matrix = new Array();
for (let i = 0; i < testStr.length - 1; i++) {
matrix[i] = [];
for (let j = 0; j < testStr.length - i - 1; j++) {
//matrix[i][j] = 0;
}
}
// i - 子串长度
// j - 起点位置
let maxString = '';
for (let i = 0; i < testStr.length - 1; i++) {
for (let j = 0; j < testStr.length - i - 1; j++) {
if (i == 0) {
matrix[i][j] = 1;
} else {
if (testStr.charAt(j) == testStr.charAt(i + j) && i == 1) {
matrix[i][j] = 2;
} else if (testStr.charAt(j) == testStr.charAt(i + j) && i > 1) {
matrix[i][j] = matrix[i - 2][j + 1] + 2;
if (maxString.length < matrix[i][j]) {
maxString = testStr.substring(j, i + j + 1)
}
} else {
// matrix[i][j] = 0;
}
}
}
}
// console.table(matrix);
console.log('maxString - ' + maxString);
console.log(testStr.indexOf(maxString));
}
function simplifyDynamicProgram(testStr) {
let date = new Date();
arrDuration.push(date.getTime());
var matrix = new Array();
for (let i = 0; i < testStr.length - 1; i++) {
matrix[i] = [];
for (let j = 0; j < testStr.length - i - 1; j++) {
//matrix[i][j] = 0;
}
}
// i - 子串长度
// j - 起点位置
let maxString = '';
// arraySubscript - 暂存 i j
// 利用 arraySubscript 来存储包含回文的小子串,简化计算量
let arraySubscript = [];
for (let i = 0; i < 3; i++) {
for (let j = 0; j < testStr.length - i - 1; j++) {
if (i == 0) {
matrix[i][j] = 1;
} else {
if (testStr.charAt(j) == testStr.charAt(i + j) && i == 1) {
matrix[i][j] = 2;
arraySubscript.push({
i,
j
});
} else if (testStr.charAt(j) == testStr.charAt(i + j) && i > 1 && matrix[i - 2][j + 1] > 0) {
matrix[i][j] = matrix[i - 2][j + 1] + 2;
arraySubscript.push({
i,
j
});
if (maxString.length < matrix[i][j]) {
maxString = testStr.substring(j, i + j + 1)
}
} else {
// matrix[i][j] = 0;
}
}
}
}
for (let k = 0; k < arraySubscript.length; k++) {
let i = arraySubscript[k].i + 2;
let j = arraySubscript[k].j - 1;
if (i + j < testStr.length && i > 0 && j > 0 && testStr.charAt(j) == testStr.charAt(i + j)) {
matrix[i][j] = i + 1;
arraySubscript.push({
i,
j
});
if (matrix[i][j] > maxString.length) {
maxString = testStr.substring(j, i + j + 1);
}
}
}
//console.table(matrix);
//console.table(arraySubscript);
console.log('maxString - ' + maxString);
console.log(testStr.indexOf(maxString));
}
function final() {
let date = new Date();
arrDuration.push(date.getTime());
let arr = [];
arr.push(arrDuration[1] - arrDuration[0]);
arr.push(arrDuration[2] - arrDuration[1]);
arr.push(arrDuration[3] - arrDuration[2]);
console.log(arr);
//console.log(date.getTime());
}
</script>
</body>
</html>