找到使2个字符串相等所需的最小移动量

时间:2013-08-28 15:03:19

标签: string algorithm

这是一个在线编码挑战(已完成)的问题 关于如何处理,我只需要一些逻辑。

问题陈述:
我们有两个字符串A和B,它们具有相同的超级字符集。我们需要更改这些字符串以获得两个相等的字符串。在每次移动中,我们都可以执行以下操作之一:

1. swap two consecutive characters of a string  
2. swap the first and the last characters of a string

可以对任一字符串执行移动 为了获得两个相等的字符串,我们需要的最小次数是多少?

输入格式和约束:
输入的第一行和第二行包含两个字符串A和B.保证它们的字符相等的超集。

1 <= length(A) = length(B) <= 2000
All the input characters are between 'a' and 'z'


输出格式:
最小移动次数打印到输出的唯一行

Sample input:
aab
baa

Sample output:
1

解释
交换字符串aab的第一个和最后一个字符,将其转换为baa。这两个字符串现在相等。

编辑:这是我的第一次尝试,但输出错误。有人可以指导我的方法有什么不妥。

int minStringMoves(char* a, char* b) {
    int length, pos, i, j, moves=0;
    char *ptr;
    length = strlen(a);

    for(i=0;i<length;i++) {
        // Find the first occurrence of b[i] in a
        ptr = strchr(a,b[i]);
        pos = ptr - a;

        // If its the last element, swap with the first
        if(i==0 && pos == length-1) {
            swap(&a[0], &a[length-1]);
            moves++;
        }
        // Else swap from current index till pos
        else {
            for(j=pos;j>i;j--) {
                swap(&a[j],&a[j-1]);
                moves++;
            }
        }

        // If equal, break
        if(strcmp(a,b) == 0)
            break;       
   }

   return moves;
}

5 个答案:

答案 0 :(得分:4)

看一下这个例子:

aaaaaaaaab
abaaaaaaaa

您的解决方案:8

aaaaaaaaab -> aaaaaaaaba -> aaaaaaabaa -> aaaaaabaaa -> aaaaabaaaa -> 
aaaabaaaaa -> aaabaaaaaa -> aabaaaaaaa -> abaaaaaaaa

正确的解决方案:2

aaaaaaaaab -> baaaaaaaaa -> abaaaaaaaa

您应该检查在另一个方向上交换是否会给您带来更好的结果。

但有时你也会破坏字符串的前一部分。例如:

caaaaaaaab
cbaaaaaaaa

caaaaaaaab -> baaaaaaaac -> abaaaaaaac

你需要另一个交换来将'c'放回到第一位。

正确的算法可能更复杂,但您现在可以看到解决方案中出现了什么问题。

答案 1 :(得分:1)

The A* algorithm可能会解决此问题。

初始节点将是原始字符串 目标节点将是目标字符串 节点的每个子节点都将是该字符串的所有可能变换 目前的成本g(x)只是到目前为止的转换次数 启发式h(x)是错误位置中字符数的一半。

由于h(x)是可接受的(因为单个转换不能在其正确的位置放置超过2个字符),目标字符串的路径将提供尽可能少的转换。

但是,基本实施可能会太慢。计算字符串的所有可能变换将相当昂贵。

请注意,节点的兄弟姐妹(其父母的子女)与其子女之间存在很多相似之处。因此,您可以只计算原始字符串的所有转换,并从那里简单地复制并重新计算涉及更改字符的数据。

答案 2 :(得分:0)

您可以使用dynamic programming。在存储所有中间结果的同时,检查所有交换的可能性以及实现目标的最少步骤数。实际上,您将计算通过应用给定规则多次可获得的每个可能目标字符串的最小步数。计算完所有后,您可以打印最小步数,这是将您带到目标字符串所需的步骤。这是JavaScript中的示例代码,以及它对“aab”和“baa”示例的用法:

function swap(str, i, j) {
   var s = str.split("");
   s[i] = str[j];
   s[j] = str[i];
   return s.join("");
}

function calcMinimumSteps(current, stepsCount)
{
   if (typeof(memory[current]) !== "undefined") {
      if (memory[current] > stepsCount) {
          memory[current] = stepsCount;
      } else if (memory[current] < stepsCount) {
          stepsCount = memory[current];
      }
   } else {
      memory[current] = stepsCount;
      calcMinimumSteps(swap(current, 0, current.length-1), stepsCount+1);
      for (var i = 0; i < current.length - 1; ++i) {
          calcMinimumSteps(swap(current, i, i + 1), stepsCount+1);
      }
   }
}

var memory = {};
calcMinimumSteps("aab", 0);
alert("Minimum steps count: " + memory["baa"]);

答案 3 :(得分:0)

以下是此问题的ruby逻辑,将此代码复制到rb文件并执行。

str1 = "education" #Sample first string
str2 = "cnatdeiou" #Sample second string

moves_count = 0
no_swap = 0
count = str1.length - 1

def ends_swap(str1,str2)    
    str2 = swap_strings(str2,str2.length-1,0)
    return str2
end

def swap_strings(str2,cp,np)
    current_string = str2[cp]
    new_string = str2[np]
    str2[cp] = new_string
    str2[np] = current_string
    return str2
end

def consecutive_swap(str,current_position, target_position)
    counter=0
    diff = current_position > target_position ? -1 : 1
    while current_position!=target_position
        new_position = current_position + diff
        str = swap_strings(str,current_position,new_position)
        # p "-------"
        # p "CP: #{current_position}   NP: #{new_position} TP: #{target_position}  String: #{str}"
        current_position+=diff
        counter+=1
    end
    return counter,str
end

while(str1 != str2 && count!=0)
    counter = 1
    if str1[-1]==str2[0]
        # p "cross match"
        str2 = ends_swap(str1,str2)
    else
        # p "No match for #{str2}-- Count: #{count}, TC: #{str1[count]}, CP: #{str2.index(str1[count])}"
        str = str2[0..count]
        cp = str.rindex(str1[count])
        tp = count
        counter, str2 = consecutive_swap(str2,cp,tp)
        count-=1        
    end
    moves_count+=counter    
    # p "Step: #{moves_count}"
    # p str2
end

p "Total moves: #{moves_count}"

请随意建议对此代码进行任何改进。

答案 4 :(得分:0)

试试这段代码。希望这会对你有所帮助。

public class TwoStringIdentical {

static int lcs(String str1, String str2, int m, int n) {
    int L[][] = new int[m + 1][n + 1];
    int i, j;

    for (i = 0; i <= m; i++) {
        for (j = 0; j <= n; j++) {
            if (i == 0 || j == 0)
                L[i][j] = 0;

            else if (str1.charAt(i - 1) == str2.charAt(j - 1))
                L[i][j] = L[i - 1][j - 1] + 1;

            else
                L[i][j] = Math.max(L[i - 1][j], L[i][j - 1]);
        }
    }

    return L[m][n];
}

static void printMinTransformation(String str1, String str2) {
    int m = str1.length();
    int n = str2.length();
    int len = lcs(str1, str2, m, n);
    System.out.println((m - len)+(n - len));
}

public static void main(String[] args) {
    Scanner scan = new Scanner(System.in);
    String str1 = scan.nextLine();
    String str2 = scan.nextLine();
    printMinTransformation("asdfg", "sdfg");
}

}