【问题标题】:find minimum steps required to change one binary string to another找到将一个二进制字符串更改为另一个所需的最少步骤
【发布时间】:2018-02-24 06:56:10
【问题描述】:

给定两个仅包含 01 的字符串 str1 和 str2,有 是将str1更改为str2的一些步骤,

step1:找到str1的一个长度为2的子串并将子串反转,str1变成str1'(str1' != str1)

step2:找到str1'的一个长度为3的子串,将子串反转,str1'变成str1'' (str1'' != str1')

以下步骤类似。

字符串长度在 [2, 30] 范围内

要求:每一步必须执行一次,不能跳过 上一步并执行下一步。

如果可以将str1改为str2,则输出所需的最小步数,否则,输出-1

示例 1

str1 = "1010", str2 = "0011",最小步长为2

首先,在 [2, 3], "1010" --> "1001",

范围内选择子字符串

然后选择 [0, 2] 范围内的子字符串,"1001" --> "0011"

示例 2

str1 = "1001", str2 = "0110", 不可能把str1改成str2, 因为在step1中,str1可以改成“0101”或者“1010”,但是在step3中,不可能改变一个length3的子串来使其不同。所以输出是-1。

示例 3

str1 = "10101010", str2 = "00101011",输出为7

我无法弄清楚示例 3,因为有两种可能性。任何人都可以就如何解决这个问题给出一些提示吗?这是什么类型的 问题?是动态规划吗?

【问题讨论】:

  • 对于算法需要的效率是否有任何限制?广度优先搜索是否“足够好”,或者该算法是否会在非常长的字符串上运行?
  • 字符串长度在 [2, 30] 范围内
  • 第 1 步很清楚,但您对第 2 步的期望是什么。??正如您在步骤 1 中所描述的,字符串范围是 [0,2] 和 [2,3]。但是为第 2 步确定的范围和预期结果是什么。
  • “每一步必须执行一次,不能跳过上一步执行下一步”中的上一步是什么。跳过它是什么意思?
  • @PetarPetrovic,这意味着我们必须执行步骤 1,然后执行步骤 2,依此类推,直到将 str1 更改为 str2。只有在执行完第 N-1 步后才能执行第 N 步。

标签: string algorithm


【解决方案1】:

这实际上是一个动态规划问题。为了解决这个问题,我们将尝试所有可能的排列,但同时记住结果。似乎有太多选项 - 有 2^30 长度为 30 的不同二进制字符串,但请记住,恢复字符串不会改变我们拥有的零和零的数量,所以上限实际上是30 choose 15 = 155117520 当我们有 15 个 0 和 1 的字符串时。大约 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++,它将是几秒钟。

【讨论】:

    【解决方案2】:

    这个问题可以使用广度优先搜索来解决。以下解决方案使用一个队列,该队列存储一对,其中当前字符串作为第一个成员,当前操作长度(最初为 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;
    

    【讨论】:

      【解决方案3】:

      将str1保存为BFS的开始,在每一步,反转所有长度为2和3的子串的值,并查看反转后形成的新字符串是否以前见过......如果没有见过...... .将它们推入队列并保持步数......如果队列前面的字符串在任何时候都是str2......那一步就是答案

      【讨论】:

        猜你喜欢
        • 2020-08-10
        • 2011-01-21
        • 2014-06-18
        • 2019-07-15
        • 1970-01-01
        • 1970-01-01
        • 2016-02-02
        • 2022-01-09
        • 1970-01-01
        相关资源
        最近更新 更多