给定两个字符串str1和str2,它们只包含
0
或1
是将str1更改为str2的一些步骤,步骤1:找到长度为2的str1子串并反转子串,str1变为str1' (str1'!= str1)
第二步:找到str1的子字符串'长度为3,并反转子串,str1'成为str1'' (str1''!= str1')
以下步骤类似。
字符串长度在[2,30]
范围内要求:每个步骤必须执行一次,我们无法跳过 前面的步骤并执行下一步。
如果可以将str1更改为str2,则输出所需的最小步数,否则输出-1
str1 =" 1010",str2 =" 0011",所需的最小步骤为2
首先,选择范围[2,3]," 1010"中的子字符串; - > " 1001",
然后选择范围[0,2]," 1001"中的子串。 - > " 0011"
str1 =" 1001",str2 =" 0110",无法将str1更改为str2, 因为在步骤1中,str1可以改为" 0101"或者" 1010",但是在步骤3中,不可能改变长度3子串以使其不同。所以输出是-1。
str1 =" 10101010",str2 =" 00101011",输出为7
我无法弄清楚示例3,因为有两种可能性。任何人都可以提供一些如何解决这个问题的提示吗?这是什么类型的 问题?它是动态编程吗?
答案 0 :(得分:0)
这实际上是一个动态编程问题。为了解决这个问题,我们将尝试所有可能的排列,但要沿途记住结果。似乎有太多的选择-2^30
个长度为30的不同二进制字符串,但是请记住,还原字符串不会更改零和1的数目,因此上限是实际上,30 choose 15 = 155117520
包含15个零和一的字符串。大约1.5亿个可能的结果还不错。
因此,从我们的start
字符串开始,我们将从到目前为止派生的每个字符串中获取所有可能的字符串,直到生成end
字符串。我们还将跟踪前辈以重建世代。这是我的代码:
start = '10101010'
end = '00101011'
dp = [{} for _ in range(31)]
dp[1][start] = '' # Originally only start string is reachable
for i in range(2, len(start) + 1):
for s in dp[i - 1].keys():
# Try all possible reversals for each string in dp[i - 1]
for j in range(len(start) - i + 1):
newstr = s
newstr = newstr[:j] + newstr[j:j+i][::-1] + newstr[j+i:]
dp[i][newstr] = s
if end in dp[i]:
ans = []
cur = end
for j in range(i, 0, -1):
ans.append(cur)
cur = dp[j][cur]
print(ans[::-1])
exit(0)
print('Impossible!')
在您的第三个示例中,这给出了序列['10101010', '10101001', '10101100', '10100011', '00101011']
-从str1到str2。如果检查字符串之间的差异,您将看到进行了哪些转换。因此,此转换可以分4个步骤完成,而不是您建议的7个步骤。
最后,这在python中要慢30倍,但是如果将其重写为C ++,将需要几秒钟的时间。
答案 1 :(得分:0)
可以使用广度优先搜索解决此问题。以下解决方案使用一个队列,该队列存储具有当前字符串作为第一成员和当前操作长度(最初为2)作为第二成员的一对。集合用于存储已经访问过的字符串,以防止进入冗余状态。对于当前字符串,我们反转每个长度为k的子字符串,其中k为当前操作长度,如果以前没有看到过,则将其添加到队列中。如果当前字符串等于所需字符串,则答案为“当前操作长度2”。如果队列为空,则不可能回答。
string str1,str2;
cin>>str1>>str2;
queue<pair<string, int>> q;
set<string> s;
q.push({str1,2});
s.insert(str1);
while(!q.empty())
{
auto p=q.front();
q.pop();
if(p.first==str2)
{
cout<<p.second-2;
return 0;
}
if(p.second<=p.first.size())
{
for(int i=0;i<=p.first.size()-p.second;i++)
{
string x=p.first;
reverse(x.begin()+i,x.begin()+i+p.second);
if(s.find(x)==s.end())
{
q.push({x,p.second+1});
s.insert(x);
}
}
}
}
cout<<-1;
答案 2 :(得分:-3)
将str1保存为BFS的开始,在每一步,反转所有长度为2和3的子串的值,看看反转后形成的新字符串之前是否见过.....如果没见过... .将它们推入队列并保持步数……如果队列前面的字符串在任何时候都是 str2 ……那一步就是答案