|
|
|
|
package class36;
|
|
|
|
|
|
|
|
|
|
// 来自网易
|
|
|
|
|
// 规定:L[1]对应a,L[2]对应b,L[3]对应c,...,L[25]对应y
|
|
|
|
|
// S1 = a
|
|
|
|
|
// S(i) = S(i-1) + L[i] + reverse(invert(S(i-1)));
|
|
|
|
|
// 解释invert操作:
|
|
|
|
|
// S1 = a
|
|
|
|
|
// S2 = aby
|
|
|
|
|
// 假设invert(S(2)) = 甲乙丙
|
|
|
|
|
// a + 甲 = 26, 那么 甲 = 26 - 1 = 25 -> y
|
|
|
|
|
// b + 乙 = 26, 那么 乙 = 26 - 2 = 24 -> x
|
|
|
|
|
// y + 丙 = 26, 那么 丙 = 26 - 25 = 1 -> a
|
|
|
|
|
// 如上就是每一位的计算方式,所以invert(S2) = yxa
|
|
|
|
|
// 所以S3 = S2 + L[3] + reverse(invert(S2)) = aby + c + axy = abycaxy
|
|
|
|
|
// invert(abycaxy) = yxawyba, 再reverse = abywaxy
|
|
|
|
|
// 所以S4 = abycaxy + d + abywaxy = abycaxydabywaxy
|
|
|
|
|
// 直到S25结束
|
|
|
|
|
// 给定两个参数n和k,返回Sn的第k位是什么字符,n从1开始,k从1开始
|
|
|
|
|
// 比如n=4,k=2,表示S4的第2个字符是什么,返回b字符
|
|
|
|
|
public class Code01_ReverseInvertString {
|
|
|
|
|
|
|
|
|
|
public static int[] lens = null;
|
|
|
|
|
|
|
|
|
|
public static void fillLens() {
|
|
|
|
|
lens = new int[26];
|
|
|
|
|
lens[1] = 1;
|
|
|
|
|
for (int i = 2; i <= 25; i++) {
|
|
|
|
|
lens[i] = (lens[i - 1] << 1) + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 求sn中的第k个字符
|
|
|
|
|
// O(n), s <= 25 O(1)
|
|
|
|
|
public static char kth(int n, int k) {
|
|
|
|
|
if (lens == null) {
|
|
|
|
|
fillLens();
|
|
|
|
|
}
|
|
|
|
|
if (n == 1) { // 无视k
|
|
|
|
|
return 'a';
|
|
|
|
|
}
|
|
|
|
|
// sn half
|
|
|
|
|
int half = lens[n - 1];
|
|
|
|
|
if (k <= half) {
|
|
|
|
|
return kth(n - 1, k);
|
|
|
|
|
} else if (k == half + 1) {
|
|
|
|
|
return (char) ('a' + n - 1);
|
|
|
|
|
} else {
|
|
|
|
|
// sn
|
|
|
|
|
// 我需要右半区,从左往右的第a个
|
|
|
|
|
// 需要找到,s(n-1)从右往左的第a个
|
|
|
|
|
// 当拿到字符之后,invert一下,就可以返回了!
|
|
|
|
|
return invert(kth(n - 1, ((half + 1) << 1) - k));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static char invert(char c) {
|
|
|
|
|
return (char) (('a' << 1) + 24 - c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 为了测试
|
|
|
|
|
public static String generateString(int n) {
|
|
|
|
|
String s = "a";
|
|
|
|
|
for (int i = 2; i <= n; i++) {
|
|
|
|
|
s = s + (char) ('a' + i - 1) + reverseInvert(s);
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 为了测试
|
|
|
|
|
public static String reverseInvert(String s) {
|
|
|
|
|
char[] invert = invert(s).toCharArray();
|
|
|
|
|
for (int l = 0, r = invert.length - 1; l < r; l++, r--) {
|
|
|
|
|
char tmp = invert[l];
|
|
|
|
|
invert[l] = invert[r];
|
|
|
|
|
invert[r] = tmp;
|
|
|
|
|
}
|
|
|
|
|
return String.valueOf(invert);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 为了测试
|
|
|
|
|
public static String invert(String s) {
|
|
|
|
|
char[] str = s.toCharArray();
|
|
|
|
|
for (int i = 0; i < str.length; i++) {
|
|
|
|
|
str[i] = invert(str[i]);
|
|
|
|
|
}
|
|
|
|
|
return String.valueOf(str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 为了测试
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
int n = 20;
|
|
|
|
|
String str = generateString(n);
|
|
|
|
|
int len = str.length();
|
|
|
|
|
System.out.println("测试开始");
|
|
|
|
|
for (int i = 1; i <= len; i++) {
|
|
|
|
|
if (str.charAt(i - 1) != kth(n, i)) {
|
|
|
|
|
System.out.println(i);
|
|
|
|
|
System.out.println(str.charAt(i - 1));
|
|
|
|
|
System.out.println(kth(n, i));
|
|
|
|
|
System.out.println("出错了!");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
System.out.println("测试结束");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|