leetcode 1012
至少有一位重复的数字
题目描述:给定正整数 N,返回小于等于 N 且具有至少 1 位重复数字的正整数的个数。
示例1:
输入:20
输出:1
解释:具有至少 1 位重复数字的正数(<= 20)只有 11 。
示例2:
输入:100
输出:10
解释:具有至少 1 位重复数字的正数(<= 100)有 11,22,33,44,55,66,77,88,99 和 100 。
示例3:
输入:1000
输出:262
提示:
1 <= N <=10^9
思路:题目要我们找出有重复数字的数字个数,反向思维,我们只要找出所有没有重复数字的数字个数total
,再用N-total
,就能得到结果
现在问题就是如何才能找到没有重复数字的数字个数
我们可以通过高低位重新组合得到,举个例子
现在要求222
的不重复数字个数
-
先去掉首位
step 1th 2th 3th total 1 0 0 1-9 9*A(9,0) 2 0 1-9 0-9 9*A(9,1)
我们解释一下这个第一步,我们把A里边的0理解为坑位,因为前面两个坑位已经被占用了,即0,因此只剩下一个坑位,而为了保证它不为0,我们用9来乘于它,然后将这个坑位让给9,也就是1-9,因此坑位就是0了,第二步同理,先让出一个坑位给9,保证首位不为0
扫描二维码关注公众号,回复: 11326032 查看本文章代码实现
for(i=j-1; i>=1; i--) total += 9*A(9,i-1);
-
考虑首位的情况
step 1th 2th 3th total 1 0-1 0-9 0-9 1*A(10-1,2) 2 2 0-1 0-9 2*A(10-2,1) 3 2 2 0-1 2*A(10-3,0)
我们分析一下第一步,A里边的
10-1
表示一个数字已经被固定好了,2表示有两个坑位,我们对这两个坑位进行分配就好了对比一下第一步,我们看第二步,第二步是先固定第一位,然后第二位在一个范围变化,
0-1
就是2,A里边的10-2
表示两个已经固定住了,1表示还要一个坑位等待分配,但是同样是0-1
,在第二步里边是2,在第一步里边确实1,为啥?因为第一步是首位,首位不能为0,因此我们将第一步的乘积去掉1个即1*A(10-1,2)
代码实现
for(i=j-1; i>=0; i--) { int num = dig[i]; for(int k=(i==j-1?1:0); k<num; k++) { if(used[k] != 0) continue; total += A(10-(j-i),i); } used[num]++; if(used[num]>1) break; if(i==0) total++; }
从上面两步我们基本知道了思路,但是有没有发现。
第二步里边其实是包含着一些带重复数的情况的,我们看一下第二步中的step3
,前面两位就是2了,因此我们还需要将重复的给剔除掉,现在问题是如何剔除这些重复数
我们维护一个数组used[10]
,用它来保存一个数是否被用过,如何理解被用过?,当前面有一个位的数字被使用过,我们在后边应当不再使用它,我们看一下具体代码
for(int k=(i==j-1?1:0); k<num; k++)
{
if(used[k] != 0)
continue;
total += A(10-(j-i),i);
}
这段代码就类似于前面第二步中step2
中的2*A(10-2,1)
,2
就是0-1
这两个数,假如一个和前面相同,我们就不用它了,因此我们不使用直接乘的方法,用累加的方法,才能剔除掉重复的。
used[num]++;
if(used[num]>1)
break;
if(i==0)
total++;
如何理解这段代码,
- 按我们的思路,这一位数字现在是变化的,在下一步我们就会将其固定住,因此先将其
used++
,反正后边的数字和它相同,而i==0, total++
,就表示原数即N
是一个无重复数字的数,你看一下完整代码肯定能理解
完整代码
#define M 10
int A(int i, int j)
{
int n, m, sum;
m=j;
sum=1;
for(n=i; m>0; i--,m--)
sum*=i;
return sum;
}
int numDupDigitsAtMostN(int N){
if(N<=10)
return 0;
int i, j, dig[M];
int total=0, flag=0;
int used[10];
i = N;
j = 0;
while(i)
{
dig[j]=i%10;
j++;
i=i/10;
}
for(i=0; i<10; i++)
used[i]=0;
for(i=j-1; i>=1; i--)
total += 9*A(9,i-1);
for(i=j-1; i>=0; i--)
{
int num = dig[i];
for(int k=(i==j-1?1:0); k<num; k++)
{
if(used[k] != 0)
continue;
total += A(10-(j-i),i);
}
used[num]++;
if(used[num]>1)
break;
if(i==0)
total++;
}
return N-total;
}
题目来源以及解法参考:
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/count-square-submatrices-with-all-ones/solution/tong-ji-quan-wei-1-de-zheng-fang-xing-zi-ju-zhen-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处