两个题目分别是考察的树的最小表示(157)和字符串的最小表示(158)。
字符串的最小表示
对于一个字符串 S S S,有众多的循环同构串,所谓最小表示就是这些循环同构串中字典序最小的那个串。我们可以采用一个 O ( n ) O(n) O(n)的算法求解出长度为 n n n的字符串的最小表示。
int n = strlen(s);
int k = 0,j = 1,i = 0;
while (i < n && j < n && k < n) {
if (s[(i + k) % n] == s[(j + k) % n]) k ++;
else {
s[(i + k) % len] > s[(j + k) % len] ? i = i + 1 + k : j = j + 1 + k;
k = 0;
if (i == j) i ++;
}
}
i = min(i, j);
最后得到的 i i i就是最小表示的起点位于原字符串中的第 i i i位。
树的最小表示
树本身没有顺序一说,但是我们可以考虑树的
D
F
S
DFS
DFS序。我们已知树的
D
F
S
DFS
DFS序其实就是在对树进行
D
F
S
DFS
DFS的过程中,每一个节点出入栈的顺序,这和
157
157
157的题目条件类似,给出了你一棵树不同的
D
F
S
DFS
DFS序,问这两种是不是表示的同一棵树。
我们如何求解树的最小表示呢?如果对每一个子树,我们都取子树的最小表示,然后对于所有的子树的最小表示按照字典序从小到大排列,最后把这些字符串拼接起来,就构成了树的最小表示串了。
所以我们的思路就是,
D
F
S
DFS
DFS找子树,对于每一棵子树我们都取他的最小表示串,最后拼接起来就可以,同时为了优化边界,我们假设这棵树初始是从个节点的子树,然后最后再返回这个节点即可。
157题解:
#include <bits/stdc++.h>
#define ill __int128
#define ll long long
#define PII pair <ll,ll>
#define ull unsigned long long
#define me(a,b) memset (a,b,sizeof(a))
#define rep(i,a,b) for (int i = a;i <= b;i ++)
#define req(i,a,b) for (int i = a;i >= b;i --)
#define ios std :: ios :: sync_with_stdio(false)
const double Exp = 1e-9;
const int INF = 0x3f3f3f3f;
const int inf = -0x3f3f3f3f;
const ll mode = 1000000007;
const double pi = 3.141592653589793;
using namespace std;
int n;
string s1, s2;
string dfs(string &str, int &u)
{
u ++; //跳过了每一个子树的进入
vector<string > now; //每一层的一个最小表示,其实就是以每一个节点为根节点看他的所有子树的最小表示
while (str[u] == '0') now.push_back(dfs(str, u));
u ++; //又跳过了最后的回溯
sort(now.begin(),now.end());
string ans = "0"; //这里要补上
for (auto i : now) ans = ans + i;
ans = ans + '1';
return ans;
}
int main()
{
ios;
cin >> n;
while ( n -- ) {
cin >> s1 >> s2;
s1 = '0' + s1 + '1';
s2 = '0' + s2 + '1';
int p1 = 0, p2 = 0;
if (dfs(s1, p1) == dfs(s2, p2)) cout << "same" << endl;
else cout << "different" << endl;
}
return 0;
}
158题解:水题
#include <bits/stdc++.h>
#define PII pair<int,int>
#define me(a, b) memset(a, sizeof(a), b)
#define ll long long
#define ull unsigned long long
#define ios std :: ios :: sync_with_stdio(false)
const int INF = 0x3f3f3f3f;
const int inf = -0x3f3f3f3f;
const double pi = acos(-1);
const int mode = 998244353;
using namespace std;
const int maxn = 1e6 + 10;
char s1[maxn], s2[maxn];
char now1[maxn], now2[maxn];
void get1(int len)
{
int k = 0,i = 0,j = 1;
while (k < len && i < len && j < len) {
if (s1[(i + k) % len] == s1[(j + k) % len]) k ++;
else {
s1[(i + k) % len] > s1[(j + k) % len] ? i = i + 1 + k : j = j + 1 + k;
k = 0;
if (i == j) i ++;
}
}
i = min(i, j);
k = 0;
for (;k < len;k++) now1[k] = s1[(i + k) % len];
return ;
}
void get2(int len)
{
int k = 0,i = 0,j = 1;
while (k < len && i < len && j < len) {
if (s2[(i + k) % len] == s2[(j + k) % len]) k ++;
else {
s2[(i + k) % len] > s2[(j + k) % len] ? i = i + 1 + k : j = j + 1 + k;
k = 0;
if (i == j) i ++;
}
}
i = min(i, j);
k = 0;
for (; k < len;k ++) now2[k] = s2[(i + k) % len];
return ;
}
int main()
{
scanf ("%s%s",s1, s2);
// cout << s1 << ' ' << s2 << endl;
int len1 = strlen(s1),len2 = strlen(s2);
get1(len1);
get2(len2);
bool flag = 1;
for (int i = 0;i < len1;i ++) {
if (now1[i] != now2[i]) {
flag = 0;
break;
}
}
if (flag) {
printf ("Yes\n");
printf ("%s\n",now1);
}
else printf ("No\n");
return 0;
}