|
|
package class44;
|
|
|
|
|
|
public class Problem_0248_StrobogrammaticNumberIII {
|
|
|
|
|
|
public static int strobogrammaticInRange(String l, String h) {
|
|
|
char[] low = l.toCharArray();
|
|
|
char[] high = h.toCharArray();
|
|
|
if (!equalMore(low, high)) {
|
|
|
return 0;
|
|
|
}
|
|
|
int lowLen = low.length;
|
|
|
int highLen = high.length;
|
|
|
if (lowLen == highLen) {
|
|
|
int up1 = up(low, 0, false, 1);
|
|
|
int up2 = up(high, 0, false, 1);
|
|
|
return up1 - up2 + (valid(high) ? 1 : 0);
|
|
|
}
|
|
|
int ans = 0;
|
|
|
// lowLen = 3 hightLen = 7
|
|
|
// 4 5 6
|
|
|
for (int i = lowLen + 1; i < highLen; i++) {
|
|
|
ans += all(i);
|
|
|
}
|
|
|
ans += up(low, 0, false, 1);
|
|
|
ans += down(high, 0, false, 1);
|
|
|
return ans;
|
|
|
}
|
|
|
|
|
|
public static boolean equalMore(char[] low, char[] cur) {
|
|
|
if (low.length != cur.length) {
|
|
|
return low.length < cur.length;
|
|
|
}
|
|
|
for (int i = 0; i < low.length; i++) {
|
|
|
if (low[i] != cur[i]) {
|
|
|
return low[i] < cur[i];
|
|
|
}
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
public static boolean valid(char[] str) {
|
|
|
int L = 0;
|
|
|
int R = str.length - 1;
|
|
|
while (L <= R) {
|
|
|
boolean t = L != R;
|
|
|
if (convert(str[L++], t) != str[R--]) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
// left想得到cha字符,right配合应该做什么决定,
|
|
|
// 如果left怎么也得不到cha字符,返回-1;如果能得到,返回right配合应做什么决定
|
|
|
// 比如,left!=right,即不是同一个位置
|
|
|
// left想得到0,那么就right就需要是0
|
|
|
// left想得到1,那么就right就需要是1
|
|
|
// left想得到6,那么就right就需要是9
|
|
|
// left想得到8,那么就right就需要是8
|
|
|
// left想得到9,那么就right就需要是6
|
|
|
// 除此了这些之外,left不能得到别的了。
|
|
|
// 比如,left==right,即是同一个位置
|
|
|
// left想得到0,那么就right就需要是0
|
|
|
// left想得到1,那么就right就需要是1
|
|
|
// left想得到8,那么就right就需要是8
|
|
|
// 除此了这些之外,left不能得到别的了,比如:
|
|
|
// left想得到6,那么就right就需要是9,而left和right是一个位置啊,怎么可能即6又9,返回-1
|
|
|
// left想得到9,那么就right就需要是6,而left和right是一个位置啊,怎么可能即9又6,返回-1
|
|
|
public static int convert(char cha, boolean diff) {
|
|
|
switch (cha) {
|
|
|
case '0':
|
|
|
return '0';
|
|
|
case '1':
|
|
|
return '1';
|
|
|
case '6':
|
|
|
return diff ? '9' : -1;
|
|
|
case '8':
|
|
|
return '8';
|
|
|
case '9':
|
|
|
return diff ? '6' : -1;
|
|
|
default:
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// low [左边已经做完决定了 left.....right 右边已经做完决定了]
|
|
|
// 左边已经做完决定的部分,如果大于low的原始,leftMore = true;
|
|
|
// 左边已经做完决定的部分,如果不大于low的原始,那一定是相等,不可能小于,leftMore = false;
|
|
|
// 右边已经做完决定的部分,如果小于low的原始,rightLessEqualMore = 0;
|
|
|
// 右边已经做完决定的部分,如果等于low的原始,rightLessEqualMore = 1;
|
|
|
// 右边已经做完决定的部分,如果大于low的原始,rightLessEqualMore = 2;
|
|
|
// rightLessEqualMore < = >
|
|
|
// 0 1 2
|
|
|
// 返回 :没做决定的部分,随意变,几个有效的情况?返回!
|
|
|
public static int up(char[] low, int left, boolean leftMore, int rightLessEqualMore) {
|
|
|
int N = low.length;
|
|
|
int right = N - 1 - left;
|
|
|
if (left > right) { // 都做完决定了!
|
|
|
// 如果左边做完决定的部分大于原始 或者 如果左边做完决定的部分等于原始&左边做完决定的部分不小于原始
|
|
|
// 有效!
|
|
|
// 否则,无效!
|
|
|
return leftMore || (!leftMore && rightLessEqualMore != 0) ? 1 : 0;
|
|
|
}
|
|
|
// 如果上面没有return,说明决定没做完,就继续做
|
|
|
if (leftMore) { // 如果左边做完决定的部分大于原始
|
|
|
return num(N - (left << 1));
|
|
|
} else { // 如果左边做完决定的部分等于原始
|
|
|
int ways = 0;
|
|
|
// 当前left做的决定,大于原始的left
|
|
|
for (char cha = (char) (low[left] + 1); cha <= '9'; cha++) {
|
|
|
if (convert(cha, left != right) != -1) {
|
|
|
ways += up(low, left + 1, true, rightLessEqualMore);
|
|
|
}
|
|
|
}
|
|
|
// 当前left做的决定,等于原始的left
|
|
|
int convert = convert(low[left], left != right);
|
|
|
if (convert != -1) {
|
|
|
if (convert < low[right]) {
|
|
|
ways += up(low, left + 1, false, 0);
|
|
|
} else if (convert == low[right]) {
|
|
|
ways += up(low, left + 1, false, rightLessEqualMore);
|
|
|
} else {
|
|
|
ways += up(low, left + 1, false, 2);
|
|
|
}
|
|
|
}
|
|
|
return ways;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// ll < =
|
|
|
// rs < = >
|
|
|
public static int down(char[] high, int left, boolean ll, int rs) {
|
|
|
int N = high.length;
|
|
|
int right = N - 1 - left;
|
|
|
if (left > right) {
|
|
|
return ll || (!ll && rs != 2) ? 1 : 0;
|
|
|
}
|
|
|
if (ll) {
|
|
|
return num(N - (left << 1));
|
|
|
} else {
|
|
|
int ways = 0;
|
|
|
for (char cha = (N != 1 && left == 0) ? '1' : '0'; cha < high[left]; cha++) {
|
|
|
if (convert(cha, left != right) != -1) {
|
|
|
ways += down(high, left + 1, true, rs);
|
|
|
}
|
|
|
}
|
|
|
int convert = convert(high[left], left != right);
|
|
|
if (convert != -1) {
|
|
|
if (convert < high[right]) {
|
|
|
ways += down(high, left + 1, false, 0);
|
|
|
} else if (convert == high[right]) {
|
|
|
ways += down(high, left + 1, false, rs);
|
|
|
} else {
|
|
|
ways += down(high, left + 1, false, 2);
|
|
|
}
|
|
|
}
|
|
|
return ways;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public static int num(int bits) {
|
|
|
if (bits == 1) {
|
|
|
return 3;
|
|
|
}
|
|
|
if (bits == 2) {
|
|
|
return 5;
|
|
|
}
|
|
|
int p2 = 3;
|
|
|
int p1 = 5;
|
|
|
int ans = 0;
|
|
|
for (int i = 3; i <= bits; i++) {
|
|
|
ans = 5 * p2;
|
|
|
p2 = p1;
|
|
|
p1 = ans;
|
|
|
}
|
|
|
return ans;
|
|
|
}
|
|
|
|
|
|
// 如果是最开始 :
|
|
|
// Y X X X Y
|
|
|
// -> 1 X X X 1
|
|
|
// -> 8 X X X 8
|
|
|
// -> 9 X X X 6
|
|
|
// -> 6 X X X 9
|
|
|
// 如果不是最开始 :
|
|
|
// Y X X X Y
|
|
|
// -> 0 X X X 0
|
|
|
// -> 1 X X X 1
|
|
|
// -> 8 X X X 8
|
|
|
// -> 9 X X X 6
|
|
|
// -> 6 X X X 9
|
|
|
// 所有的len位数,有几个有效的?
|
|
|
public static int all(int len) {
|
|
|
int ans = (len & 1) == 0 ? 1 : 3;
|
|
|
for (int i = (len & 1) == 0 ? 2 : 3; i < len; i += 2) {
|
|
|
ans *= 5;
|
|
|
}
|
|
|
return ans << 2;
|
|
|
}
|
|
|
|
|
|
// 我们课上讲的
|
|
|
public static int all(int len, boolean init) {
|
|
|
if (len == 0) { // init == true,不可能调用all(0)
|
|
|
return 1;
|
|
|
}
|
|
|
if (len == 1) {
|
|
|
return 3;
|
|
|
}
|
|
|
if (init) {
|
|
|
return all(len - 2, false) << 2;
|
|
|
} else {
|
|
|
return all(len - 2, false) * 5;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|