剑指 Offer II 086. 分割回文子字符串

给定一个字符串 s ,请将 s 分割成一些子串,使每个子串都是 回文串 ,返回 s 所有可能的分割方案。

回文串 是正着读和反着读都一样的字符串。

示例 1:

输入:s = “google”
输出:[[“g”,“o”,“o”,“g”,“l”,“e”],[“g”,“oo”,“g”,“l”,“e”],[“goog”,“l”,“e”]]

字符串的回溯,经典

class Solution {
	vector<vector<string>> res;
	string str;
	int slen;
public:
	bool isHuiWen(int leftPoint, int rightPoint, int leftEdge, int rightEdge){
		int tmpL = leftPoint;
		int tmpR = rightPoint;
		while(tmpL >= leftEdge && tmpR <= rightEdge) {
			if(str[tmpL/2] != str[tmpR/2]) {
				return false;
			}
			
			tmpL-=2;
			tmpR+=2;
		}
		return true;
	}
	// 这里的start的范围是从 0 ~ 2 * s.length() - 1
	// 但是传递的时候, start 永远是偶数,即停留在实体字符上
	// 0、2、4、...、slen-1
	void partitionHelper(vector<string> &v, int start) {
		if (start >= slen) {
			res.push_back(v);
			return;
		}
		
		int i = start;

		// 以j为圆心
		//for(int j = i;  j < slen; j++) 
		for(int j = i;  2*j < slen + i; j++) {
			//判定以j为中心,左边界到i,右边界小于slen的圆圈是否是回文
			//如果是的话,则将园内的数据一股脑儿放到v中,然后从右侧圆外进入纵深
			//纵深回来后,再将该数据取出来,继续进行下一个圆心的遍历
			//i和j固定后,左半径长度 j-i+1,设右边界为y,则y-j+1 = j-i+1 => y=2*j-i
			//所以,j 的范围有如下要求:
			// 2*j-i < slen
			// 推出 2*j < slen + i
			// 因为 i<slen,所以,j<slen 可以缩小为 2*j < slen + i
			
			//圆心j确定后,半径也随之确定,j-i+1 (包括圆心)
			//同前一个回文问题,j的下标为奇数时,肯定为*,所以左右侧遍历要从 j-1 和 j+1 向两边扩散
			//同前一个回文问题,j的下标为偶数时,肯定为实体字符,所以左右侧遍历要从 j 和 j 向两边扩散
			//扩散的步进为2
			
			//该圆满足条件,圆长 (j-1 - i + 1)*2+1 = 2j-2i+1
			if(j%2) {
				if(isHuiWen(j-1, j+1, i, 2*j-i)) {
					v.push_back(str.substr(i/2, (2*j-2*i + 1)/2+1));
					partitionHelper(v, 2*j-i+2);
					v.pop_back();
				}
			} else {
				if(isHuiWen(j, j, i, 2*j-i)) {
					v.push_back(str.substr(i/2, (2*j-2*i + 1)/2+1));
					partitionHelper(v, 2*j-i+2);
					v.pop_back();
				}					
			}
		}
	}

    vector<vector<string>> partition(string s) {
		vector<string> tmp;
		slen = 2 * s.length() - 1;
		if(slen <= 0) {
			return res;
		}

		str = s;
		partitionHelper(tmp, 0);
		return res;
    }
};

以 abac为例,可以假想为:a * b * a * c
0 1 2 3 4 5 6
a * b * a * c

核心是如下函数:

void partitionHelper(vector<string> &v, int start) {
	if (start >= slen) {
		res.push_back(v);
		return;
	}
	
	int i = start;

	// 以j为圆心
	for(int j = i;  2*j < slen + i; j++) {
		if(j%2) {
			if(isHuiWen(j-1, j+1, i, 2*j-i)) {
				v.push_back(str.substr(i/2, (2*j-2*i + 1)/2+1));
				partitionHelper(v, 2*j-i+2);
				v.pop_back();
			}
		} else {
			if(isHuiWen(j, j, i, 2*j-i)) {
				v.push_back(str.substr(i/2, (2*j-2*i + 1)/2+1));
				partitionHelper(v, 2*j-i+2);
				v.pop_back();
			}					
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值