【模拟】直接验证至少包含(2,5,6,9)中的一个,可以包含(0,1,8)其他不能包含。O(nlogn)的复杂度,因为要把所有数都枚举一遍,还要枚举每个数的每一位。
class Solution {
Set<Character> a = new HashSet(){{
add('0');
add('1');
add('8');
}};
Set<Character> b = new HashSet(){{
add('2');
add('5');
add('6');
add('9');
}};
boolean count(String x) {
int n = x.length();
char[] s = x.toCharArray();
int flag = 0;
for (var i = 0; i < n; i++) {
char c = s[i];
if (a.contains(c)) ;
else if (b.contains(c)) flag = 1;
else return false;
}
return flag == 1;
}
public int rotatedDigits(int n) {
int ans = 0;
for (var i = 1; i <= n; i++) {
String str = Integer.toString(i);
if (count(str)) ans++;
}
return ans;
}
}
【数位DP】用f(pos, diff, limit)来表示第pos位,是否包含一个2,5,6,9并且不包含(3,4,7),limit表示是否受到边界限制,如果受到边界限制,那么只能填0-s[pos]范围,并且填了s[pos]后下面还是继续受限制,否则可以填0-9。
class Solution {
// 数位dp 6:45
// 用f(pos, diff, limit)
int[][][] dp;
char[] s;
int n;
int[] tab = new int[] {0, 0, 1, -1, -1, 1, 1, -1, 0, 1};
public int f(int pos, int diff, boolean limit) {
int lim = limit? 1: 0;
if (pos == n) {
if (diff == 0) return 0;
return 1;
}
if (dp[pos][diff][lim] >= 0) {
// System.out.println(dp[pos][diff][lim]);
return dp[pos][diff][lim];
}
int up;
if (limit) {
up = s[pos] - '0';
} else {
up = 9;
}
int res = 0;
for (var i = 0; i <= up; i++) {
if (tab[i] != -1) {
if (tab[i] == 1) {
res += f(pos + 1, 1, limit && i == up);
// System.out.println(ans);
} else {
res += f(pos + 1, diff, limit && i == up);
// System.out.println(ans);
}
}
}
dp[pos][diff][lim] = res;
return res;
}
public int rotatedDigits(int n) {
s = String.valueOf(n).toCharArray();
this.n = s.length;
dp = new int[n + 1][2][2];
for (var i = 0; i <= n; i++) {
for (var j = 0; j < 2; j++) Arrays.fill(dp[i][j], -1);
}
return f(0, 0, true);
}
}