使用BFS将一个字符串转换为另一个字符串

时间:2014-10-13 19:06:48

标签: string algorithm graph breadth-first-search

有一个字符串,其字符只能是'a','b'或'$',字符串中只有一个'$'。

在每一步,我们都可以按如下方式修改字符串:

  1. '$'可以与其相邻字符交换,例如“a $ ba”可以更改为“$ aba”或“ab $ a”。

  2. 只有当相邻字符与相邻字符旁边不同时,才能将$字符与相邻字符旁边交换。 (例如'aba $ ab'可以转换为'a $ abab'或'ababa $',但'ab $ aab'不能转换为'abaa $ b',因为'a'不能跳过'a')

  3. 您将获得两个字符串,即初始状态和最终状态(长度将相同),您必须输出将初始状态下的字符串更改为最终状态字符串所需的最少步骤数。

    如何使用广度优先搜索解决此问题?

    例如:
    字符串s1,s2;
    输入:s1 = a $ b,s2 = ab $
    输出:1
    输入:s1 = aba $ a,s2 = $ baaa
    输出:2

4 个答案:

答案 0 :(得分:2)

在Python中:

from collections import deque

def swap(s, a, b):
    a, b = min(a,b), max(a,b)
    if 0 <= a < b < len(s):
        return s[:a] + s[b] + s[a] + s[b+1:]

def rotate(s, a, b):
    a, b = min(a,b), max(a,b)
    if 0<= a < b < len(s) and len(set(s[a:b+1])) == 3:
        return s[:a] + s[b:a:-1] + s[a] + s[b+1:]

def push(Q, changes, s):
    if s is not None:
        Q.append((changes, s))

def bfs(s1, s2):
    Q = deque()
    Q.append((0, s1))

    while Q:
        changes, s = Q.popleft()

        if s == s2: 
            return changes

        pos = s.index('$')

        push(Q, changes+1, swap(s, pos, pos-1))
        push(Q, changes+1, swap(s, pos, pos+1))
        push(Q, changes+1, rotate(s, pos, pos+2))
        push(Q, changes+1, rotate(s, pos-2, pos))


print bfs('a$b', 'ab$')
print bfs('abaa$a', 'b$aaaa')
print bfs('aba$a', '$baaa')

答案 1 :(得分:1)

在C ++中,

#include <iostream>
#include <cstring>
#include <queue>

using namespace std;

int size;

struct str
{
    char a[1000];
    int change;
};

int position(char a[], char b)
{
    for(int i = 0; i < size; i++) {
        if(a[i] == b)
            return i;
    }
    return -1;
}

void swap(char a[], int pos, int shift)
{   
    int temp = a[pos];
    a[pos] = a[pos + shift];
    a[pos + shift] = temp;
}

int minChange(char arr[], char out[])
{
    std::queue <str> q;

    str i;
    strcpy(i.a, arr);
    i.change = 0;

    q.push(i);

    while(!q.empty()) {
        str fin = q.front();
        q.pop();
        if(strcmp(out, fin.a) == 0)
            return fin.change;

        int pos = position(fin.a, '$');

        if(pos > 0) {
            str temp;
            strcpy(temp.a, fin.a);
            swap(temp.a, pos, -1);
            temp.change = fin.change + 1;
            q.push(temp);
        }
        if(pos < size - 1) {
            str temp;
            strcpy(temp.a, fin.a);
            swap(temp.a, pos, 1);
            temp.change = fin.change + 1;
            q.push(temp);
        }
        if(pos > 1 && (fin.a[pos - 1] != fin.a[pos - 2])) {
            str temp;
            strcpy(temp.a, fin.a);
            swap(temp.a, pos, -2);
            temp.change = fin.change + 1;
            q.push(temp);
        }
        if(pos < size - 2 && (fin.a[pos + 1] != fin.a[pos + 2])) {
            str temp;
            strcpy(temp.a, fin.a);
            swap(temp.a, pos, 2);
            temp.change = fin.change + 1;
            q.push(temp);
        }
    }
}


int main()
{
    size = 3;
    cout<<minChange("a$b", "ab$")<<endl;
    size = 6;
    cout<<minChange("abaa$a", "b$aaaa")<<endl;
    size = 5;
    cout<<minChange("aba$a", "$baaa")<<endl;    
}

答案 2 :(得分:0)

问题可以通过广度优先搜索解决,如下所示,使用类似C#的伪代码语法。

string FinalState; (to be assigned the final state)

int DistanceToFinalState(string CurrentState)
{
  if (CurrentState == FinalState)
  {
    return 0; // end of recursion - strings match, distance is zero
  }
  else
  {
    int val1 = Infinity;
    int val2 = Infinity;
    int val3 = Infinity;
    int val4 = Infinity;
    if ($ is not at the leftmost position of CurrentState)
      val1 = DistanceToFinalState(CurrentState with $ moved to the left);
    if ($ is not at the rightmost position of CurrentState)
      val2 = DistanceToFinalState(CurrentState with $ move to the right);
    if ($ has 2 chars left to it)
      val3 = DistanceToFinalState(CurrentState with $ moved 2 chars to the left with the 2 skipped characters reversed);
    if ($ has 2 chars right to it)
      val4 = DistanceToFinalState(CurrentState with $ moved 2 chars to the right with the 2 skipped characters reversed);
    return minumum of {val1, val2, val3, val4};
  }
}

初始问题可以通过评估DistanceToFinalState(InitialState)来解决。

答案 3 :(得分:0)

在Java中:

private static int findTime(String s1, String s2) {
    Queue<String> queue = new LinkedList<>();
    queue.add(s1);
    Map<String, Boolean> visited = new HashMap<>();
    while (!queue.isEmpty()) {
        String in = queue.poll();
        Boolean isVisited = visited.get(in);
        if (isVisited != null && isVisited)
            continue;
        visited.put(in, true);
        int index = in.indexOf('$');
        //First case...
        if ((index + 1) < in.length()) {
            String in1 = in.substring(0, index) + in.charAt(index + 1) + "$";
            if ((index + 2) < in.length()) {
                in1 += in.substring(index + 2);
            }
            if (in1.equals(s2)) {
                return log(visited.size() + 1, 2);
            }
            if (in1.length() == s2.length()) {
                queue.add(in1);
            }
        }
        if (index > 0) {
            String in2 = "$" + in.charAt(index - 1) + in.substring(index + 1);
            if ((index - 2) >= 0) {
                in2 = in.substring(0, index - 1) + in2;
            }
            if (in2.equals(s2))
                return log(visited.size() + 1, 2);
            if (in2.length() == s2.length()) {
                queue.add(in2);
            }
        }
        //Second case...
        if ((index + 2) < in.length()) {
            if (in.charAt(index + 1) != in.charAt(index + 2)) {
                String in1 = in.substring(0, index) + in.charAt(index + 2)
                        + in.charAt(index + 1) + "$";
                if ((index + 3) < in.length()) {
                    in1 += in.substring(index + 3);
                }
                if (in1.equals(s2))
                    return log(visited.size() + 1, 2);
                if (in1.length() == s2.length()) {
                    queue.add(in1);
                }
            }
        }
        if (index - 1 > 0) {
            if (in.charAt(index - 1) != in.charAt(index - 2)) {
                String in2 = "$" + in.charAt(index - 1) + in.charAt(index - 2) +
                        in.substring(index + 1);
                if ((index - 3) >= 0) {
                    in2 = in.substring(0, index - 2) + in2;
                }
                if (in2.equals(s2))
                    return log(visited.size() + 1, 2);
                if (in2.length() == s2.length()) {
                    queue.add(in2);
                }
            }
        }
    }
    return 0;
}

static int log(int x, int base) {
    return (int) (Math.log(x) / Math.log(base));
}

System.out.println(findTime("a$b", "ab$"));
System.out.println(findTime("aba$a", "$baaa"));
System.out.println(findTime("abaa$a", "b$aaaa"));