You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

217 lines
6.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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;
}
}
}