【问题标题】:Minimum number of swaps to convert a string into another string [duplicate]将字符串转换为另一个字符串的最小交换次数[重复]
【发布时间】:2014-05-15 14:26:20
【问题描述】:

问题陈述:

找到将一个字符串转换成另一个相同长度的字符串的最小交换次数,这可能有也可能没有重复的字符;允许任意交换。

min_swaps('kamal', 'amalk') -> 3
#       1         2        3
# kamal -> lamak -> aamlk -> amalk

注意:关于 SO 有很多这样的问题,但似乎没有一个适用于任意交换。

初步方法:

let s1 = 'kamal'
let s2 = 'amalk'

假设 s1 是“正确的”排序,即它的元素从0 -> N-1 以递增的顺序映射到序列。

0 1 2 3 4
k a m a l

现在创建一个数组 P,它是从 s2 中的字母到 s1 中正确索引的映射:

1 2 3 4 0
a m a l k 

P = [1,2,3,4,0]

现在我们可以使用修改后的归并排序来计算 P 中的数组反转次数,这将给我们提供无序元素的数量。

修改归并排序:

int main(int argc, char ** argv) {
   int array[] = { 1,2,3,4,0 };

   int array_size = sizeof(array)/sizeof(array[0]);
   int inversions = merge_sort(array, 0, array_size - 1);

   printf("Found %d inversions\n", inversions);
   return 0;
}

int merge_sort(int a[], int start, int end) {
   if ( end > start ) {
      int mid = start + (end - start) / 2;
      int x = merge_sort(a, start, mid);
      int y = merge_sort(a, mid + 1, end);
      int z = merge(a, start, mid, end);

      return x + y + z;
   }

   return 0;
}

int merge(int a[], int start, int mid, int end) {
   int l = start, r = mid + 1;
   int i = 0;
   int temp[end - start + 1];
   int splitInversionCount = 0;

   while ( l <= mid && r <= end ) {
       if ( a[l] < a[r] ) {
          temp[i++] = a[l++];
       }
       else {
         splitInversionCount += mid - l + 1;
         temp[i++] = a[r++];
       }
   }

   // copy whichever half of the array remains
   while ( l <= mid ) {
      temp[i++] = a[l++];
   }

   while ( r <= end ) {
      temp[i++] = a[r++];
   }

   // copy temp back into a
   int k;
   for(k = 0; k < i; k++) {
      a[k + start] = temp[k];
   }

   return splitInversionCount;
}

这样做的问题是它给出了仅与相邻元素交换的最小数量,这将返回 4 而不是 3

问题:

有没有办法扩展这个算法来捕获任意交换?还是我需要一种完全不同的方法?

【问题讨论】:

标签: c algorithm


【解决方案1】:

我还没有完整的解决方案,但我认为说明这一点对帮助他人很有用。

假设字符串的大小为N。让我们调用k 已经在其位置的字符数。最初k &lt;= N

交换可以有:

  1. 在正确的位置设置 2 个字符。将k 增加 2
  2. 在正确的位置设置 1 个字符。将k 增加 1
  3. 什么都不做,k 保持不变。

你总是可以进行第二种移动,而且你可以在 O(n) 时间内找到它。只需从pos中取出一个字符,找到它需要的位置,然后交换即可。

您不应该在看到第一种类型时立即进行交换,因为您可能会破坏同时设置 2 个字符的其他动作。如果你这样做了,你最终会在 3 步中设置 4 个字符,而你本可以在 2 步中完成。

进行第三种走法可能允许进行两种第一种走法,因此所有三种走法都是有用的。

【讨论】:

  • 如何证明你的贪心?什么可以保证大小超过 2(N 个成员)的圈子不会在 N 次交换而不是 N-1 次中得到解决?
  • @Толя 我不是在提出一个贪心算法,我只是在陈述一些关于这个问题的想法,试图找到一个解决方案。实际上,我开始怀疑贪婪的存在。我正在阅读 Sergey L. 发布的链接,但我的数学不太好。
猜你喜欢
  • 2013-08-19
  • 1970-01-01
  • 2014-12-08
  • 1970-01-01
  • 1970-01-01
  • 2014-06-13
  • 2016-07-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多