LeetCode 0005 -- 最长回文子串

本文深入探讨了寻找字符串中最长回文子串的问题,提供了两种算法解决方案:暴力法和中心扩展法。通过示例解释了每种方法的实现过程,比较了它们的时间和空间复杂度。

最长回文子串

题目描述

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"

解题思路

个人AC

暴力法。

class Solution {
    public String longestPalindrome(String s) {
        if (s == null) {
            throw new IllegalArgumentException("Input array can't null");
        }
        
        int n = s.length();
        if (n <= 1) {
            return s;
        }
        String lsp = ""; // Longest Sub Palindrome
        for (int i = 1; i < n; i++) {
            for (int j = 0; j <= i; j++) {
                String sub = s.substring(j, i + 1);
                // 验证每个字符串需要O(n)的复杂度
                if (isPalindrome(sub) && sub.length() > lsp.length()) {
                    lsp = sub;
                    break;
                }
            }
        }
        return lsp;
    }
    
    private boolean isPalindrome(String s) {
        int i = 0, j = s.length() - 1;
        while (i < j) {
            if (s.charAt(i++) != s.charAt(j--)) {
                return false;
            }
        }
        return true;
    }
}

时间复杂度: O ( n 3 ) O(n^3) O(n3)

空间复杂度: O ( 1 ) O(1) O(1)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZeDiPxEF-1572699192179)(assets/1572674018725.png)]

有执行结果可见,代码效率太低,需要进一步优化代码逻辑!

最优解

动态规划

应当避免在验证子字符串是否回文时进行不必要的重复计算。

...
中心扩展

可以观察到回文串中心的两侧互为镜像,因此判断字符串是否回文可以从它的中心向外展开,并且只有2n - 1个这样的中心。

为什么是2n - 1个中心,而不是n个中心?

因为当字符串包含偶数个元素时,其中心将处在两字母之间。

class Solution {
    public String longestPalindrome(String s) {
        if (s == null || s.length() == 0) return "";
        int start = 0, end = 0; // 记录最长回文子串在原字符串中的起始位置
        for (int i = 0; i < s.length(); i++) {
            // 倘若回文串为ABA类型
            int len1 = expandAroundCenter(s, i, i);
            // 倘若回文串为ABBA类型
            int len2 = expandAroundCenter(s, i, i + 1);
            int len = Math.max(len1, len2);
            // 更新最长回文子串的起始位置
            if (len > end - start) {
                start = i - (len - 1) / 2;
                end = i + len / 2;
            }
        }
        return s.substring(start, end + 1);
    }
    
    // 从字符串中心分别向两边扩展,返回能找到的最长的回文串的长度
    private int expandAroundCenter(String s, int left, int right) {
        int L = left, R = right;
        while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) {
            L--;
            R++;
        }
        return R - L - 1;
    }
}

时间复杂度: O ( n 2 ) O(n^2) O(n2),围绕中心向两边扩展只需要 O ( n ) O(n) O(n)的复杂度;

空间复杂度: O ( 1 ) O(1) O(1)

先展示下效果 https://pan.quark.cn/s/a4b39357ea24 遗传算法 - 简书 遗传算法的理论是根据达尔文进化论而设计出来的算法: 人类是朝着好的方向(最优解)进化,进化过程中,会自动选择优良基因,淘汰劣等基因。 遗传算法(英语:genetic algorithm (GA) )是计算数学中用于解决最佳化的搜索算法,是进化算法的一种。 进化算法最初是借鉴了进化生物学中的一些现象而发展起来的,这些现象包括遗传、突变、自然选择、杂交等。 搜索算法的共同特征为: 首先组成一组候选解 依据某些适应性条件测算这些候选解的适应度 根据适应度保留某些候选解,放弃其他候选解 对保留的候选解进行某些操作,生成新的候选解 遗传算法流程 遗传算法的一般步骤 my_fitness函数 评估每条染色体所对应个体的适应度 升序排列适应度评估值,选出 前 parent_number 个 个体作为 待选 parent 种群(适应度函数的值越小越好) 从 待选 parent 种群 中随机选择 2 个个体作为父方和母方。 抽取父母双方的染色体,进行交叉,产生 2 个子代。 (交叉概率) 对子代(parent + 生成的 child)的染色体进行变异。 (变异概率) 重复3,4,5步骤,直到新种群(parentnumber + childnumber)的产生。 循环以上步骤直至找到满意的解。 名词解释 交叉概率:两个个体进行交配的概率。 例如,交配概率为0.8,则80%的“夫妻”会生育后代。 变异概率:所有的基因中发生变异的占总体的比例。 GA函数 适应度函数 适应度函数由解决的问题决定。 举一个平方和的例子。 简单的平方和问题 求函数的最小值,其中每个变量的取值区间都是 [-1, ...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值