问题:给定一个字符串,我们可以任意旋转该字符串,返回字典序最小的字符串表示。
-
假设给定我们的字符串是s,首先我们将s复制一遍接到s的尾部,假设字符串长度为n,当我们枚举起点start在返回0~n-1时就可以得到所有字符串的表示。
-
初始让i=0, j=1,比较s[i+k]、s[j+k],用k表示相对于i、j的偏移位置,如果相等的话让k++,直到比较到第一个不相等的位置,假设s[i+k]>s[j+k],则说明对于起点在i~i+k的字符串都不是原串的最小表示,可以更新i为i+k+1;反之可以更新j。
-
更新过程中如果i==j,则需要让两者错开,可以让i++即可,最后返回min(i, j)即可,这个位置就是字符串对应的最小表示的起点。
问题描述
-
问题链接:AcWing 158. 项链
分析
- 求出两个串的最小表示,比较是否相等即可。
代码
- C++
#include3. 力扣上的最小表示法题目 Leetcode 0796 旋转字符串#include using namespace std; const int N = 2000010; int n; char a[N], b[N]; int get_min(char s[]) { int i = 0, j = 1; while (i < n && j < n) { int k = 0; while (k < n && s[i + k] == s[j + k]) k++; if (s[i + k] > s[j + k]) i += k + 1; else j += k + 1; if (i == j) i++; } int k = min(i, j); s[k + n] = 0; return k; } int main() { scanf("%s%s", a, b); n = strlen(a); memcpy(a + n, a, n); memcpy(b + n, b, n); int x = get_min(a), y = get_min(b); if (strcmp(a + x, b + y)) puts("No"); else { puts("Yes"); puts(a + x); } return 0; }
题目描述:Leetcode 0796 旋转字符串
分析
-
本题的考点:最小表示法。
-
求出两个串的最小表示,比较是否相等即可。
-
假设给定我们的字符串是s,首先我们将s复制一遍接到s的尾部,假设字符串长度为n,当我们枚举起点start在返回0~n-1时就可以得到所有字符串的表示。
-
初始让i=0, j=1,比较s[i+k]、s[j+k],用k表示相对于i、j的偏移位置,如果相等的话让k++,直到比较到第一个不相等的位置,假设s[i+k]>s[j+k],则说明对于起点在i~i+k的字符串都不是原串的最小表示,可以更新i为i+k+1;反之可以更新j。
-
更新过程中如果i==j,则需要让两者错开,可以让i++即可,最后返回min(i, j)即可,这个位置就是字符串对应的最小表示的起点。
代码
- C++
class Solution {
public:
bool rotateString(string A, string B) {
if (A.size() != B.size()) return false;
return get_min(A) == get_min(B);
}
string get_min(string s) {
int n = s.size();
s = s + s;
int i = 0, j = 1;
while (i < n && j < n) {
int k = 0;
while (k < n && s[i + k] == s[j + k]) k++;
if (s[i + k] > s[j + k]) i += k + 1;
else j += k + 1;
if (i == j) i++;
}
int k = min(i, j);
return s.substr(k, n);
}
};
- Java
class Solution {
public boolean rotateString(String A, String B) {
if (A.length() != B.length()) return false;
return get_min(A).equals(get_min(B));
}
private String get_min(String s) {
int n = s.length();
StringBuilder sb = new StringBuilder();
sb.append(s).append(s);
char[] cs = sb.toString().toCharArray();
int i = 0, j = 1;
while (i < n && j < n) {
int k = 0;
while (k < n && cs[i + k] == cs[j + k]) k++;
if (cs[i + k] > cs[j + k]) i += k + 1;
else j += k + 1;
if (i == j) i++;
}
int k = Math.min(i, j);
return sb.substring(k, k + n).toString();
}
}
时空复杂度分析
-
时间复杂度: O ( n ) O(n) O(n),n为字符串长度。
-
空间复杂度: O ( n ) O(n) O(n)。



