leetcode#248 中心对称数 III
题目:
中心对称数是指一个数字在旋转了 180 度之后看起来依旧相同的数字(或者上下颠倒地看)。
写一个函数来计算范围在 [low, high] 之间中心对称数的个数。
示例:
输入: low = "50", high = "100"
输出: 3
解释: 69,88 和 96 是三个在该范围内的中心对称数
思路:
数位dp。
计算位数小于字符串位数的个数,计算长度相等时的个数最后相加。
代码:
class Solution
{
public:
bool check(string &s)
{
if (s.length() == 1)
return true;
string tmp = s.substr(0, s.length() / 2);
reverse(tmp.begin(), tmp.end());
for (auto &i : tmp)
if (i == '6')
i = '9';
else if(i=='9')
i = '6';
return tmp <= s.substr((s.length() + 1) / 2);
}
int count(string str)
{
int res = 0;
int len = str.length();
//计算位数少于字符串位数的个数 因为位数少,所以每一位没有限制
for (int i = 1; i < len; ++i)
{
int num = i / 2;
if (i & 1)
{
if (num <= 1)
res += pow(4, num) * 3;
else
res += 4 * pow(5, num - 1) * 3;
}
else
res += 4 * pow(5, num - 1);
}
//计算位数和字符串位数相等的个数、
//dp[i][j] 小于第j位的个数和等于第j位的个数。
const int equal = 0, less = 1;
vector<char> choice1 = {'0', '1', '6', '8', '9'};
vector<vector<int>> dp(2, vector<int>(len / 2 + 1, 0));
dp[equal][0] = 1;
for (int i = 1; i <= len / 2; ++i)
{
char ch = str[i - 1];
dp[less][i] += (i == 1 ? 4 : 5) * dp[less][i - 1];
int j;
for (j = (i == 1 ? 1 : 0); j < 5 && choice1[j] < ch; ++j)
dp[less][i] += dp[equal][i - 1];
if (choice1[j] == ch)
dp[equal][i] += dp[equal][i - 1];
}
//加上上面计算出的结果 分奇偶,如1234112中 1234321不符合
if (len & 1)
{
int i;
char ch = str[len / 2];
vector<char> choice2{'0', '1', '8'};
res += 3 * dp[less][len / 2];
for (i = 0; i < 3 && choice2[i] < ch; ++i)
res += dp[equal][len / 2];
if (i != 3 && choice2[i] == ch && check(str))
res += dp[equal][len / 2];
}
else
{
res += dp[less][len / 2];
if (check(str))
res += dp[equal][len / 2];
}
return res;
}
int strobogrammaticInRange(string low, string high)
{
//范围不正确
if (stol(low) > stol(high))
return 0;
//返回count(hight)-count(low-1);
if (!stol(low))
return count(high);
low = to_string(stol(low) - 1);
return count(high) - count(low);
}
};