LeetCode周赛#111 Q4 Find the Shortest Superstring(状压DP)

题目来源:https://leetcode.com/contest/weekly-contest-111/problems/find-the-shortest-superstring/

问题描述

 943. Find the Shortest Superstring

Given an array A of strings, find any smallest string that contains each string in A as a substring.

We may assume that no string in A is substring of another string in A.

 

Example 1:

Input: ["alex","loves","leetcode"]
Output: "alexlovesleetcode"
Explanation: All permutations of "alex","loves","leetcode" would also be accepted.

Example 2:

Input: ["catg","ctaagt","gcta","ttca","atgcatc"]
Output: "gctaagttcatgcatc"

 

Note:

  1. 1 <= A.length <= 12
  2. 1 <= A[i].length <= 20

------------------------------------------------------------

题意

定义一个字符串集合S的母串sp为一个使得∀s∈S, s==substr(sp) . 给定一组字符串,已知没有任何一个字符串是另一个的子串,求这组字符串的最短母串(如有多个,给出任意一个即可)。

------------------------------------------------------------

思路

字符串为节点字符串之间的共同前缀后缀长度为边,建立有向图。问题转化为求有向图的最长哈密顿道路

建图过程:对于字符串集合中的字符串a与字符串b, 如果a[-i:] == b[0:i],则从a向b连一条长度为i的有向边,表示a的后缀与b的前缀共用,b在a后;同理,如果a[0:j] == b[-j:],则从b向a连一条长度为j的有向边,表示b的后缀与a的前缀共用,a在b后。

最长哈密顿道路:回忆最短哈密顿道路的题目POJ 3311 Hie with the Pie(状压DP),我们用状态压缩动态规划求解。同样,最长哈密顿道路也可以用状压DP求解。用dp[s][i]表示经过的节点组成的状态为s的时候,到达节点i所经过的长度,其中(s & (1<<j))表示状态s是否经过节点j. 从1到(1<<n)-1遍历状态s,最终取dp[(1<<n)-1][i](i=0,1,…,n-1)中的最大者,就是最长哈密顿道路。

回溯:由于题目要求输出路径,所以求出最长哈密顿道路的长度之后,还要回溯找到最长哈密顿道路的各个节点的顺序,按顺序输出。采用的方法是令dp数组的元组为一个类,类属性包括道路长度和前驱节点,并置起始节点的前驱为-1,反向回溯直至遇到-1节点,可以得到逆序的路径,再逆序输出即可。

------------------------------------------------------------

代码

class Solution {
public:
	const static int NMAX = 12;
	class node {
	public:
		int len, pre;	// len: length of Hamilton path; pre: pre string id

		node(void) : len(0), pre(-1) {}
		node(int len, int pre) : len(len), pre(pre) {}
	};
	int n;
	int mat[NMAX][NMAX] = {};
	node dp[1 << NMAX][NMAX];

	void build_graph(vector<string>& A)
	{
		n = A.size();
		int i, j, k, si, sj;
		for (i = 0; i < n-1; i++)
		{
			for (j = i + 1; j < n; j++)
			{
				si = A[i].size();
				sj = A[j].size();
				for (k = 0; k < si; k++)
				{
					string s = A[i].substr(k);
					if (s == A[j].substr(0, si - k))
					{
						mat[i][j] = si - k;
						break;
					}
				}
				for (k = 0; k < sj; k++)
				{
					string s = A[j].substr(k);
					if (s == A[i].substr(0, sj - k))
					{
						mat[j][i] = sj - k;
						break;
					}
				}
			}
		}
	}

	void hamilton()
	{
		int s, i, j, lmax, imax;
		for (s = 1; s < (1 << n); s++)
		{
			for (i = 0; i < n; i++)
			{
				lmax = 0;
				imax = -1;
				if (s & (1 << i))
				{
					for (j = 0; j < n; j++)
					{
						if (i != j && (s & (1<<j))
							&& dp[s - (1 << i)][j].len + mat[j][i] >= lmax)
						{
							lmax = dp[s - (1 << i)][j].len + mat[j][i];
							imax = j;
						}
					}
				}
				dp[s][i].len = lmax;
				dp[s][i].pre = imax;
			}
		}
	}

	string recall(vector<string>& A)
	{
		string ret;
		vector<int> seq;
		int i, lmax = 0, s = (1<<n) - 1, j;
		for (i = 0; i < n; i++)
		{
			if (dp[s][i].len >= lmax)
			{
				lmax = dp[s][i].len;
				j = i;
			}
		}
		while (j != -1)
		{
			seq.push_back(j);
			i = j;
			j = dp[s][j].pre;
			s -= (1 << i);
		}
		ret.append(A[seq[n - 1]]);
		for (i = n - 2; i >= 0; i--)
		{
			ret.append(A[seq[i]].substr(mat[seq[i + 1]][seq[i]]));
		}
		return ret;
	}

	string shortestSuperstring(vector<string>& A) {
		if (A.size() == 1)
		{
			return A[0];
		}
		build_graph(A);
		hamilton();
		return recall(A);
	}
};

猜你喜欢

转载自blog.csdn.net/da_kao_la/article/details/84229165
Q4