一、题目描述
Strings A
and B
are K
-similar (for some non-negative integer K
) if we can swap the positions of two letters in A
exactly K
times so that the resulting string equals B
.
Given two anagrams A
and B
, return the smallest K
for which A
and B
are K
-similar.
Example 1:
Input: A = “ab”, B = “ba”
Output: 1
Example 2:
Input: A = “abc”, B = “bca”
Output: 2
Example 3:
Input: A = “abac”, B = “baca”
Output: 2
Example 4:
Input: A = “aabc”, B = “abca”
Output: 2
二、题目分析
由题可知,我们需要求解从初始状态(A
或B
,这里设为A
)转换到目标状态(B
)所需的最小步骤数K
,即求从图的一个顶点到另一顶点的最短路径长度。因为图是未知的,所以这里采用BFS的策略求解。首先最简单的想法就是从起点A
出发,BFS遍历所有可到达的顶点(状态),这样做虽然可行,但显然复杂度太高,需要进一步优化。在最简单的BFS中,很显然有些交换字符的步骤是多余的,而为了达到目的,交换字符后A
字符串的相应位置至少要有一个字符与B
的相应位置处的字符相同,即 A[j] == B[i]
的时候我们可以交换 A[i]
和 A[j]
使得 A[i] == B[i]
,当然,最理想的情况是当 A[i] == B[j] && A[j] == B[i]
时交换,这样交换后A
、B
中 i
、j
两处位置的字符就都一致了。另外,若 A[j] == B[j]
,则不应再交换 A[j]
处的字符。
通过上面的条件,我们排除了一些不必要的路径。若能找到最理想的条件我们就可以直接“走”这条路径,而在交换后只有一个字符能相符的情况下我们就需要对所有情况进行检查了。实际上,我们只需按顺序依次遍历 A
的每一个位置,按上述条件进行对比,只要有一处符合交换条件,我们就可以接受该情况,再从该情况出发进行BFS,这样就能很大程度上减少计算次数。而因为我们依序遍历(以i
作为迭代下标),并且在只有一个字符能够符合的情况下我们需要检查所有符合条件的交换位置(所有符合 A[j] == B[i]
的 j
),所以即使在其它位置存在最理想的交换情况我们也不会错过。
三、具体实现
依上所述,采用递归实现。
class Solution
{
public:
int kSimilarity( string A, string B )
{
int len = A.size(), pos = 0, k = INT_MAX;
list<int> swapIdxes;
for ( int i = 0; i < len; ++i ) {
if ( A.at( i ) == B.at( i ) )
continue;
bool best = false, fit = false;
pos = i;
for ( int j = i + 1; j < len; ++j ) {
if ( A.at( j ) != B.at( i ) ||
A.at( j ) == B.at( j ) )
continue;
fit = true;
if ( A.at( i ) == B.at( j ) ) {
swapIdxes.clear();
swapIdxes.push_back( j );
best = true;
break;
}
swapIdxes.push_back( j );
}
if ( best || fit )
break;
}
for ( int i : swapIdxes ) {
swap( A[pos], A[i] );
k = min( k, 1 + kSimilarity( A.substr( pos + 1 ), B.substr( pos + 1 ) ) );
swap( A[pos], A[i] );
}
if ( swapIdxes.empty() )
return 0;
return k;
}
};