【笔试题】寻找字符串的最长回文子串

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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值