现在的位置: 首页 > 综合 > 正文

Scramble String

2017年12月23日 ⁄ 综合 ⁄ 共 2470字 ⁄ 字号 评论关闭

 题目描述为:

Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.

Below is one possible representation of s1 = "great":

    great
   /    \
  gr    eat
 / \    /  \
g   r  e   at
           / \
          a   t

To scramble the string, we may choose any non-leaf node and swap its two children.

For example, if we choose the node "gr" and swap its two children, it produces a scrambled string"rgeat".

    rgeat
   /    \
  rg    eat
 / \    /  \
r   g  e   at
           / \
          a   t

We say that "rgeat" is a scrambled string of "great".

Similarly, if we continue to swap the children of nodes "eat" and"at", it produces a scrambled string
"rgtae".

    rgtae
   /    \
  rg    tae
 / \    /  \
r   g  ta  e
       / \
      t   a

We say that "rgtae" is a scrambled string of "great".

Given two strings s1 and s2 of the same length, determine ifs2 is a scrambled string of
s1.

 

====================================

第一反应模拟肯定是不可能的,再仔细看scramble实际就是选取一个节点然后旋转,所以明显对一个节点旋转两次必定是一样的。

如果能把大问题化成递归的小问题那就好解决了。

1.首先我们看例子中的"great" 它的旋转只能是分成两半:要么这两半交换位置要么不交换,如题中可以看出是gr 为一半,eat为一半,在结果子串"rgate"可以看到两半的相对位置是没有改变的。于是我们可以递归地检查前一半的两个子串是否是合法的,以及后一半是否是合法的;当均只有一个字符的时候直接比较是否相等。

但也有可能两半相对位置有变化: 比如 s1="gr | eat" ,s2=" ate | rg",可以看到两半相对位置有变化,这时我们需要递归检查s1前一半和s2后一半是否合法,以及s1后一半和s2前一半是否合法。

2.刚开始被题目误导了还以为是二分,实际上不是,我们必须枚举所有分法比如 s1 = "g | reat" = "gr | eat " = "gre | at" = "grea | t ”,每一种都要检查一次,当然如果哪一次检查成功了就可以直接返回了。

3.在确定了分半之后,我们还需要检查s1跟s2中分半的对应问题,即是前一半对后一半还是后一半对前一半,这个好解决,因为题目保证两个子串字符相同只是位置不同,所以加入我们当前假设分半是 'gr | eat" ,我们只需要为前一半建立出现次数记录,然后检查s2中前一半出现的字符是否跟它一样,如果是那就是前一半对前一半;同理我们也可以检查是否是前一半对后一半,注意这两种情况并非是互斥的,可能两种都符合,但是只有一种是合理的,所以两种对应都要检查。

4.代码: 44ms过大集合

#include<iostream>
#include<vector>
#include<string>
#include<cassert>
using namespace std;

bool containAll(const string& s1,int st1,int end1,const string& s2,int st2,int end2)
{
	vector<int> visit(256,0);
	int len=end1-st1+1;
	for(int i=0;i<len;i++)
		visit[s1[st1+i]]++;

	bool ans=true;
	for(int i=0;i<len;i++)
	{
		if (visit[s2[st2+i]]<=0)
		{
			ans=false;
			break;
		}
		visit[s2[st2+i]]--;
	}
	return ans;
}

bool isOK(string& s1,int st1,int end1,string& s2,int st2,int end2)
{
	if (st1>end1 && st2>end2)
		return true;
	if (st1==end1&&st2==end2)
		return s1[st1]==s2[st2];

	bool ans=false;
	for(int len=1;len<=(end1-st1);len++)
	{
		int right=end1-st1+1-len;
		int loc=st2;
		
		
		if (containAll(s1,st1,st1+len-1,s2,st2,st2+len-1))
		{
			ans= isOK(s1,st1,st1+len-1,s2,st2,st2+len-1)&&isOK(s1,st1+len,end1,s2,st2+len,end2);
		}
		if (ans)
			break;
		if (containAll(s1,st1,st1+right-1,s2,st2+len,end2))
		{
			ans= isOK(s1,st1,st1+right-1,s2,st2+len,end2)&&isOK(s1,st1+right,end1,s2,st2,st2+len-1);			
		}
		if (ans)
			break;
	}
	return ans;
}

bool isScramble(string s1,string s2)
{
	int sz1=s1.size();
	int sz2=s2.size();
	if (sz1!=sz2) return false;
	return isOK(s1,0,sz1-1,s2,0,sz2-1);
}


int main()
{
	string s1,s2;
	while((cin>>s1)&&s1.compare("-1")!=0)
	{
		cin>>s2;
		bool ans=isScramble(s1,s2);
		cout<<ans<<endl;
	}
}

 

抱歉!评论已关闭.