求出1 ~ 13的整数中1出现的次数,并算出100 ~ 1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
数位dp,剑指offer
解题思路:对于数据过大的题目而言有两种考虑
* 推公式
* 考虑数位dp
对于这道题目,我看到的第一眼就觉得有点像是数位dp,于是写了一个数位dp的解法,用于解题同时复习数位dp
数位dp:每一位具有一个状态,状态可以传递,及前面出现的数字可以决定某种状态即为数位dp,
就这道题而言:当出现数字1即达到计数条件,可以使用数位dp
// c++ 代码如下:
#include <iostream>
using namespace std;
int num[11] = { 0 };
int dp[11][11] = { 0 };
int dfs(int pos, int pn, int lmt)
{
if (pos == 0)return pn;
if (dp[pos][pn] && !lmt)return dp[pos][pn];
int top = lmt ? num[pos] : 9;
int ans = 0;
int tn = 0;
for (int i = 0; i <= top; i++)
{
if (i == 1)tn = pn + 1;
else tn = pn;
ans += dfs(pos - 1, tn, lmt && (i == top));
}
if (!lmt)dp[pos][pn] = ans;
return ans;
}
int solve(int n)
{
memset(dp, 0, sizeof(int));
int k = 0;
while (n) {
num[++k] = n % 10;
n = n / 10;
}
int ans = dfs(k, 0, 1);
return ans;
}
int main()
{
int n;
cin >> n;
int ans = 0;
cout << solve(n) - solve(0) << endl;
return 0;
}
代码比较简单,如有不解之处参考类似题目
我的另一篇博客:数位DP——2018数,吉比特笔试题
博客具有详细注释
求和
练手时写的,思考方向还行,所以贴出来
class Solution {
public:
vector<int> FindNumbersWithSum(vector<int> num, int s) {
vector<int> ans;
int first = 0, last = num.size() - 1;
while (first < last) {
if (num[first] + num[last] > s)last--;
else if (num[first] + num[last] < s)first++;
else break;
}
if (first < last) {
ans.push_back(num[first]);
ans.push_back(num[last]);
}
return ans;
}
};