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

2 years ago
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;
}
}
}