您的位置:首页 > 编程语言 > C语言/C++

关于digit统计算法(C语言实现)

2016-08-22 18:00 597 查看
在练习题目的时候,遇到了这个问题:对输入的整数进行digit的处理。具体处理如:统计完全平方数且有至少两个字位相同。

最初的想法是需要一个数组进行存储计算出来的数位,再遍历判断是否有两个相同的数位。

这种做法肯定可行,但是需要考虑,如果是静态设定数组的位数,比如:

int arr[10]


那么,想一想,要是恰好是10个digits,那么以上的逻辑就没有问题,但是,要是,只用到了其中的一部分呢?那么没有用到的就是0了,这样判断的时候,0的个数为大于等于2了能算满足吗?

肯定不行!

这样申请的数组必须是恰好是我们得到的数位个数。比如,123,可以得到1,2,3,那么这个数组必须恰好存储三个元素,才能进行下一步判断。

好了,直接看题目(来源于PAT训练题–基础题 :)):

本题要求实现一个函数,判断任一给定整数N是否满足条件:它是完全平方数,又至少有两位数字相同,如144、676等。

函数接口定义:

int IsTheNumber ( const int N );


其中N是用户传入的参数。如果N满足条件,则该函数必须返回1,否则返回0。

裁判测试程序样例:

#include<stdio.h>
#include <math.h>
int IsTheNumber ( const int N );
int main()
{
int n1, n2, i, cnt;
scanf("%d %d", &n1, &n2);
cnt = 0;
for ( i=n1; i<=n2; i++ ) {
if ( IsTheNumber(i) )
cnt++;
}
printf("cnt = %d\n", cnt);
return 0;
}
/* 你的代码将被嵌在这里 */


输入样例:105 500

输出样例:

cnt = 6

我首先想到了一个特别复杂的实现,用的是单链表,动态分配堆空间:

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
///time:2016-8-22

//定义数组结点
typedef struct Node{ //Node是结构体的名字
int data;
struct Node* next;
} INode,*INodeList;//声明数据类型名

int IsTheNumber(const int N){
int n = N;
int result = 0;
//no.1 : is n*n type
//no.2 : split digits, at least two are the same
double root = sqrt(N);
int ce = ceil(root);
int fl = floor(root);
//如果上取整和下取整相同,则是个完全平方数,否则就不是,直接令result为0
if(ce != fl){
result = 0;
}
else{
//分配新数组,L作为头结点,用头结点的data值存储结点个数
INodeList L = (INodeList)malloc(sizeof(INode));
L->next = NULL;
L->data = 0;
//头插法建立单链表
while(n != 0){
INodeList p = (INodeList)malloc(sizeof(INode));
p->data = n % 10;
p->next = L->next;
L->next = p;
n /= 10;
L->data = L->data+1;//结点个数加1
}
//因为每一个元素都是0-9,所以可以采用水桶法,共需要十个桶
int container[10];
for(int i = 0; i < 10; i++){
container[i] = 0;//初始化为0
}

INodeList q = L->next;
//检查桶里面搜集的元素
while(q != NULL){
container[q->data]++;
q = q->next;
}
//遍历桶,如果有桶的元素大于等于2则返回true
for(int i = 0; i < 10; i++){
if(container[i] >= 2){
result = 1;
}
}
}
return result;
}

int main()
{
int n1, n2, i, cnt;

scanf("%d %d", &n1, &n2);
cnt = 0;
for ( i=n1; i<=n2; i++ ) {
if ( IsTheNumber(i) )
cnt++;
}
printf("cnt = %d\n", cnt);

return 0;
}


但是这个做法是可以优化的,即:完全不用单链表,因为这个算法的核心在桶,仅需要一个固定的container存储0-9数位即可,那么简化版本是:

int IsTheNumber(const int N){
int n = N;
int result = 0;
//no.1 : is n*n type
//no.2 : split digits, at least two are the same
double root = sqrt(N);
int ce = ceil(root);
int fl = floor(root);
if(ce != fl){
result = 0;
}
else{
//因为每一个元素都是0-9,所以可以采用水桶法,共需要十个桶
int container[10];
for(int i = 0; i < 10; i++){
container[i] = 0;//初始化为0
}
while(n != 0){
container[n % 10]++;
n /= 10;
}
//遍历桶,如果有桶的元素大于等于2则返回true
for(int i = 0; i < 10; i++){
if(container[i] >= 2){
result = 1;
}
}
}
return result;
}


总结:第一种解法用来练习结构体的使用是很好的。

这里的两个要点:

如何得到digit

如何用桶收集相关数据

具体代码中已经有详细演示,不再多说。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言 算法
相关文章推荐