-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProblem_0854_kSimilarity.cc
189 lines (177 loc) · 4.47 KB
/
Problem_0854_kSimilarity.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include <functional>
#include <iostream>
#include <queue>
#include <string>
#include <unordered_set>
#include <vector>
#include "UnitTest.h"
using namespace std;
class Solution
{
public:
int minSwap(const string &s1, const string &s2, const int &pos)
{
int tot = 0;
for (int i = pos; i < s1.size(); i++)
{
tot += s1[i] != s2[i];
}
return (tot + 1) / 2;
}
// dfs
int kSimilarity1(string s1, string s2)
{
string str1, str2;
for (int i = 0; i < s1.size(); i++) // 相同字符不用参与交换
{
if (s1[i] != s2[i])
{
str1.push_back(s1[i]);
str2.push_back(s2[i]);
}
}
int n = str1.size();
if (n == 0)
{
return 0;
}
// 因为每一次有效交换,可以将s1的字符调整到与s2相同,这样只需调整n-1个字符,最后一个字符也一定相等
int ans = n - 1; // 最多交换n - 1
function<void(int, int)> dfs = [&](int pos, int cost) {
if (cost > ans)
{
return;
}
while (pos < n && str1[pos] == str2[pos])
{
pos++;
}
if (pos == n)
{
ans = min(ans, cost);
return;
}
/* 当前状态的交换次数下限大于等于当前的最小交换次数 */
if (cost + minSwap(str1, str2, pos) >= ans)
{
return;
}
for (int i = pos + 1; i < n; i++)
{
if (str1[i] == str2[pos])
{
std::swap(str1[i], str1[pos]);
dfs(pos + 1, cost + 1);
std::swap(str1[i], str1[pos]);
}
}
};
dfs(0, 0);
return ans;
}
// bfs
int kSimilarity2(string s1, string s2)
{
int N = s1.size();
queue<pair<string, int>> q;
unordered_set<string> visit;
q.emplace(s1, 0);
visit.emplace(s1);
for (int step = 0;; step++)
{
int sz = q.size();
for (int i = 0; i < sz; i++)
{
// cur 表示当前 s1 调整后的新字符串
// pos 表示当前cur[0 ... pos-1] == s2[0 ... pos-1],需要从pos开始尝试交换
string cur = q.front().first;
int pos = q.front().second;
q.pop();
if (cur == s2)
{
// 满足条件
return step;
}
while (pos < N && cur[pos] == s2[pos])
{
// 剪枝,如果 cur[0 ... pos] 和s2[0 ... pos] 之间的字符相等,就不用尝试交换
pos++;
}
// 从 pos 开始尝试交换
for (int j = pos + 1; j < N; j++)
{
// 这里cur[pos] != s2[pos]
if (cur[j] != s2[j] && cur[j] == s2[pos])
{
// 当 cur[j] == s2[j] 时,交换cur[pos]和cur[j]反而增加了交换次数
// 同时最终结果又不一定符合条件
// 剪枝,只在 cur[j] != s2[j] 时去交换
std::swap(cur[pos], cur[j]);
if (!visit.count(cur))
{
visit.emplace(cur);
q.emplace(cur, pos + 1);
}
std::swap(cur[pos], cur[j]);
}
}
}
}
}
void process(string &s1, string &s2, int index, int cost, int &step)
{
if (index == s1.size())
{
// 这时s1 == s2,需要结算答案
step = std::min(step, cost);
return;
}
if (cost >= step)
{
// 如果cost >= step,说明没有必要继续尝试
return;
}
if (s1[index] != s2[index]) // 不相等才交换
{
for (int i = index + 1; i < s1.size(); i++)
{
// 这里已经满足s1[index] != s2[index]
// 如果s1[i] == s2[i],这时交换反而增加了交换次数
if (s1[i] != s2[i] && s1[i] == s2[index])
{
swap(s1[index], s1[i]);
// 尝试下一个位置,cost + 1
process(s1, s2, index + 1, cost + 1, step);
swap(s1[index], s1[i]);
}
}
}
else
{
// 本次没交换,cost不变
process(s1, s2, index + 1, cost, step);
}
}
int kSimilarity3(string s1, string s2)
{
int ans = s1.length() - 1;
process(s1, s2, 0, 0, ans);
return ans;
}
};
void testKSimilarity()
{
Solution s;
EXPECT_EQ_INT(1, s.kSimilarity1("ab", "ba"));
EXPECT_EQ_INT(2, s.kSimilarity1("abc", "bca"));
EXPECT_EQ_INT(1, s.kSimilarity2("ab", "ba"));
EXPECT_EQ_INT(2, s.kSimilarity2("abc", "bca"));
EXPECT_EQ_INT(1, s.kSimilarity3("ab", "ba"));
EXPECT_EQ_INT(2, s.kSimilarity3("abc", "bca"));
EXPECT_SUMMARY;
}
int main()
{
testKSimilarity();
return 0;
}