LeetCode-Longest Palindromic Substring

算法分析与设计,第二周博客

Longest Palindromic Substring

Description:

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example:

Input: "babad"

Output: "bab"

Note: "aba" is also a valid answer.

Example:

Input: "cbbd"

Output: "bb"

  本题的题意是要找出一个字符串中最长的回文子串。在此之前,需要理解两个概念:

  1. 回文:指的是一个字符串,从头读到尾和从尾读到头的结果是一样的。
  2. 子串:指的是一个字符串从某一处开始一直连续到某一处结尾,注意需要与子序列区别开来。
判断一个字符串是否是回文的代码如下:
boolean isPalindrome(String s) {
		int n = s.length();
		for (int i = 0; i < n/2; ++i) {
			if (s.charAt(i) != s.charAt(n-i-1))
				return false;
		}
		return true;
	}

这个算法的时间复杂度为O(n)。
再次回到这个问题上来,要解决这个问题,最简单的一个方法就是找出这个字符串的所有子串,一个个的判断其是否为回文,并找出属于回文中的最长的那一个。实现的代码如下:
 
public String longestPalindrome(String s) {
		String res = "";
		int start = 0, end = 0;
		int n = s.length();
		for (int i = 0; i < n; ++i) {
			for (int j = i+1; j <= n; ++j) {
				String cur = s.substring(i, j);
				if (isPalindrome(cur) && cur.length() > res.length())
					res = cur;
			}
		}
		return res;
    }
这个算法的时间复杂度为O(n^3),理所当然的超时了... O(n^3)的时间复杂度太高了,需要找到一个更加好的算法。
再次回到回文这个点上来。我们用P(i, j)来代表字符串s的从下标i到下标j的子串是否为回文,也就是:
P(i, j) = true 如果s.substring(i, j+1)是回文。
观察回文,可以发现以下两个性质,设字符串s是回文,长度为n:
  1. s[0] == s[n-1]
  2. s.substring(1,n-1)也是回文
所有的回文都具备以上两个性质,而满足以上两个条件的字符串也必定是回文。也就是说,以上两个条件是一个字符串是回文的充分必要条件。
另外有以下两个简单的初始的性质:
  1. P(i, i) = true
  2. P(i, i+1) = s[i] == s[i+1]
有了这几个性质,就可以简化算法了:
P(i, j) = s[i] == s[j] && (i == j || i+1 == j || P(i+1, j-i) );
如果用一个二维数组将P存储起来,那么就只需要为这个表中的每个值赋值就可以得到结果了。这样的算法时间复杂度是O(n^2)。实现代码如下:
for (int i = n-1; i >= 0; --i) {
        	for (int j = i+1; j < n; ++j) {
        		if (s.charAt(i) == s.charAt(j) && (i == j || i+1 == j || p[i+1][j-1] == 1))
        			p[i][j] = 1;
        	}
        }
在这个算法中,需要注意的是,在为p[i][j]赋值时,需要提前把p[i+1][j-1]的值确定,这也就要求需要从下往上开始赋值,所以第一个循环是从n-1到0,而不是从0到n-1。
得到了这个有关子串是否是回文的二维数组后,只需要在这个数组中把最长的那个子串找出来就可以了。代码如下:
int start = 0, end = 0;
        for (int i = 0; i < n; ++i) {
            for (int j = i+1; j < n; ++j) {
                if (p[i][j] == 1 && j-i > end-start) {
                    end = j;
                    start = i;
                }
            }
        }
        return s.substring(start, end+1);
确定二维数组的值和找出最长子串的时间复杂度都是O(n^2),所以整个程序的复杂度也是O(n^2)。全部代码如下:

class Solution {

	public String longestPalindrome(String s) {
		int n = s.length();
		int[][] p = new int[n][n];
        for (int i = n-1; i >= 0; --i) {
        	for (int j = i; j < n; ++j) {
        		if (s.charAt(i) == s.charAt(j) && (i == j || i+1 == j || p[i+1][j-1] == 1))
        			p[i][j] = 1;
        	}
        }
        int start = 0, end = 0;
        for (int i = 0; i < n; ++i) {
            for (int j = i+1; j < n; ++j) {
                if (p[i][j] == 1 && j-i > end-start) {
                    end = j;
                    start = i;
                }
            }
        }
        return s.substring(start, end+1);
    }

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值