问题描述
给定两个等长字符串A和B,它们所含的字符个数及种类完全一样,问最少需要对A执行多少次交换字符才能使得A变成B?
分析
因为这个问题数据规模很小,只包含6种字符、A和B的长度都不超过20,所以暴力+适当剪枝的思路就能够通过。
首先对于A[i]==B[i]的部分,完全不需要做任何处理;
其次,对于A[i]!=B[i]的部分,显然需要找A[j]来跟A[i]进行交换,A[j]满足A[j]==B[i]。在这个过程中,如果A[i]==B[j],那自然是“意外之喜”,“一箭双雕”,“一石二鸟”。可以很自信的想:如果能够一箭双雕,必然是最优策略。但是,如果没有“一箭双雕”,那就只能逐个尝试寻找最优的 j 了。假设就选择了j,交换完后得到新的字符串A',可以递归调用求solve(A’,B)。 在这个递归过程中,因为B是不变的,这个函数只要A确定,返回值就定下来了。所以可以用备忘录方法(记忆化搜索)来加速递归。站在更宏观的角度考虑这个问题,把每个A字符串当做结点,每一次swap操作会形成新的结点并添加一条边,以上递归的过程相当于深度优先搜索。如果改写成广度优先搜索,运行效率必定能够提高。
站在更宏观的角度考虑这个问题,这是一个很艰难的图论问题。问题等价于寻找有向图的边的一个覆盖,使得每一个子集都是环,要使环数最大。这个问题似乎是个NP问题。
但是贪心的方式足以通过此题。 贪心法则如下:- 选择每个顶点的最小环构成一个最小环集合,对此集合执行去重操作。
- 如果环集合中存在结点数为1的环,必然选择之。
- 如果环集合中存在结点数为2的环,必然选择之。
- 否则,执行以下步骤。
- 对于这个环集合,统计图中边的使用次数。
- 对每个环,求它边的平均使用次数作为这个环的value。
- 优先消去value最小的环
这个问题等价于:
给定一个可以包含重复元素的数组,最少需要执行多少次swap操作,才能使数组变得有序。C++递归写法
class Solution {public: unordered_mapmp; int kSimilarity(string A, string B) { if(A