LeetCode 2002. 两个回文子序列长度的最大乘积

本文介绍了一种算法问题,即在给定字符串中找到两个不相交的回文子序列,使得它们长度的乘积最大。通过状态压缩和DFS两种方法详细解析了求解过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给你一个字符串 s ,请你找到 s 中两个 不相交回文子序列 ,使得它们长度的 乘积最大 。两个子序列在原字符串中如果没有任何相同下标的字符,则它们是 不相交 的。

请你返回两个回文子序列长度可以达到的 最大乘积 。

子序列 指的是从原字符串中删除若干个字符(可以一个也不删除)后,剩余字符不改变顺序而得到的结果。如果一个字符串从前往后读和从后往前读一模一样,那么这个字符串是一个 回文字符串 。

示例 1:

example-1

输入:s = "leetcodecom"
输出:9
解释:最优方案是选择 "ete" 作为第一个子序列,"cdc" 作为第二个子序列。
它们的乘积为 3 * 3 = 9 。
示例 2:

输入:s = "bb"
输出:1
解释:最优方案为选择 "b" (第一个字符)作为第一个子序列,"b" (第二个字符)作为第二个子序列。
它们的乘积为 1 * 1 = 1 。
示例 3:

输入:s = "accbcaxxcxx"
输出:25
解释:最优方案为选择 "accca" 作为第一个子序列,"xxcxx" 作为第二个子序列。
它们的乘积为 5 * 5 = 25 。
 

提示:

2 <= s.length <= 12
s 只含有小写英文字母。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-product-of-the-length-of-two-palindromic-subsequences
 

解法一:状态压缩

本题的数据范围为[2, 12],所以本题可以利用状态压缩找出所有的回文子序列后,再对没有相交的回文子序列进行两两相乘,取最大的乘积。

class Solution {

	bool check(const string &str, const int &len)
	{
		for (int i = 0; i < len - i; i++)
		{
			if (str[i] != str[len - 1 - i])
				return false;
		}
		return true;
	}

public:
	int maxProduct(string s) {
		int len = s.length();
		int num = 1 << len;
		vector<pair<int, int>> ps;
		for (int i = 1; i < num; ++i)
		{
			string str = "";
			int count = 0;
			for (int j = 0; j < len; ++j)
			{
				if ((i&(1 << j)) == (1 << j))
				{
					str += s[j];
					++count;
				}
			}
			if (check(str, count))
				ps.push_back(make_pair(i, count));
		}
		int pLen = ps.size();
		int ans = 0;
		for (int i = pLen-1; i >=0; --i)
		{
			for (int j = i + 1; j < pLen; ++j)
			{
				if ((ps[i].first&ps[j].first) == 0) //判断这两子序列是否相交
					ans = max(ans, ps[i].second*ps[j].second);
			}
		}
		return ans;
	}
};

 方法二:dfs

对于字符串中的每个字符,可以在最终答案的子序列1中,也可以在子序列2中,也可以都不在。根据这种思路进行dfs。

class Solution {

	int ans;

	bool check(const string &s)
	{
		int len = s.length();
		for (int i = 0; i < len - 1 - i; ++i)
		{
			if (s[i] != s[len - 1 - i])
				return false;
		}
		return true;
	}
    //对于s1与s2,也可以用引用提升速度
	void dfs(const string &s, const int &n, string &s1, string &s2, int nowId)
	{
		if (nowId == n)
		{
			if (check(s1) && check(s2))
				ans = max(ans, (int)(s1.length()*s2.length()));
			return;
		}
		dfs(s, n, s1, s2, nowId + 1);
        s1+=s[nowId];
		dfs(s, n, s1, s2, nowId + 1);
        s1.pop_back();    //移除最后一个的时间复杂度为O(1)
        s2+=s[nowId];
		dfs(s, n, s1, s2, nowId + 1);
        s2.pop_back();
		return;
	}

public:
	int maxProduct(string s) {
		ans = 0;
		string s1 = "", s2 = "";
		int n = s.length();
		dfs(s, n, s1, s2, 0);
        return ans;
	}
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值