【LeetCode】最长回文子串的四种解题方法

21 篇文章 0 订阅

1.暴力法

	string longestPalindrome(string s) {
		if (s == "") {
			return "";
		}
		int len = s.length();
		for (int i = len; i > 0; i--) {
			for (int begin = 0; begin + i-1 < len; begin++) {
				string ss = s.substr(begin, i);
				if (isPal(ss)) {
					return ss;
				}
			}
		}
		return "";
	}

	bool isPal(string s) {
		if (s == "") {
			return true;
		}
		string s1 = s;
		reverse(s1.begin(),s1.end());
		if (s == s1) {
			return true;
		}
		return false;
	}

2.倒置字符串,求出原字符串和倒置字符串的最长公共子串,注意下标对应问题(判断最后一个位置即可),下标不对应代表不是回文

	string longestPalindrome(string s) {
		if (s == "") {
			return "";
		}
		string s1 = s;
		reverse(s1.begin(), s1.end());
		int m = s.length() + 1;
		int** arr = new int*[m];
		for (int i = 0; i < m; i++) {
			arr[i] = new int[m];
		}
		for (int i = 0; i < m; i++) {
			arr[0][i] = 0;
			arr[i][0] = 0;
		}
		//储存最大位置
		int max = 0, max_i = 0;
		for (int i = 1; i < m; i++) {
			for (int j = 1; j < m; j++) {
				if (s[i - 1] == s1[j - 1]) {
					arr[i][j] = arr[i - 1][j - 1] + 1;
					//更新最大值位置
					if (arr[i][j] > max) {
						//判断下标是否对应
						if ((m - 2) - (j - 1) + arr[i][j] - 1 == i - 1) {
							max = arr[i][j];
							max_i = i - 1;
						}

					}
				}
				else {
					arr[i][j] = 0;
				}
			}
		}
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < m; j++) {
				cout << arr[i][j];
			}
			cout << endl;
		}
		//取出公共字符串
		string maxPal = s.substr(max_i - max + 1, max);
		return maxPal;
	}

3.动态规划法(暴力算法的优化)

按长度递增依次遍历所有长度,长度为一二时单独考虑,为其它时从一二递推即可,首尾相同且去掉首尾为回文,则本身为回文

	string longestPalindrome(string s) {
		if (s == "") {
			return "";
		}
		int len = s.length();
		string maxPal = "";
		//P中存下标之间是否是回文
		int** P = new int*[len];
		for (int i = 0; i < len; i++) {
			P[i] = new int[len];
		}
		for (int i = 0; i < len; i++) {
			for (int j = 0; j < len; j++) {
				P[i][j] = 0;
			}
		}
		//计算最长回文子串
		int _start = 0, _len = 0;
		for (int i = 1; i <= len; i++) {
			for (int begin = 0; begin + i <= len; begin++) {
				int end = begin + i - 1;
				//递推式(长度依次递增,但保存了短的情况,长的只需递推即可,不需要重复计算)
				if ((i == 1 || i == 2 || P[begin + 1][end - 1]) && s[begin] == s[end]) {
					P[begin][end] = 1;
					_start = begin;
					_len = i;
				}
			}
		}
		maxPal = s.substr(_start, _len);
		return maxPal;
	}

4.中心拓展法

中心有单中心和双中心,所以共有2n-1个中心,向两边拓展

	string longestPalindrome(string s) {
		if (s == "") {
			return "";
		}
		int len = s.length();
		if (len == 1) {
			return s;
		}
		string maxPal = "";
		int maxLen = 0, start = 0;
		for (int i = 0; i < len - 1; i++) {
			int len1 = longestAroundCenter(s, i, i);
			if (len1 > maxLen) {
				maxLen = len1;
				start = i - len1 / 2;
			}
			int len2 = longestAroundCenter(s, i, i + 1);
			if (len2 > maxLen) {
				maxLen = len2;
				start = i - len2 / 2 + 1;
			}
		}
		maxPal = s.substr(start, maxLen);
		return maxPal;
	}

	int longestAroundCenter(string s, int i, int j) {
		int left = i, right = j;
		if ((left >= 0) && (right <= s.length() - 1) && (s[left] == s[right])) {
			left--;
			right++;
		}
		return right - left + 1 - 2;//最后拓展的不符合需要减去
	}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值