C语言数学问题常见归纳

C语言编程

一.数学问题

  1. 进制转换问题

    • 10进制转换N进制

      通过不断地取模取余,存放在数组里面,再通过逆序输出出来即可

      注意:如果是转换为大于10进制的数,例如十六进制,那么我们取模的数要分情况:

      1.若大于10,则需要转化为A-F,这时候我们就需要字符数组来进行存储,最后输出按字符输出即可

      2.若小于10,则直接+'0',变成字符来参与运算,最后加入字符数组

    • M进制转换为10进制

      通过不断地相乘相加,即可完成转换任务,为了操作的方便性可以直接用字符数组来进行输入,当M>10时,里面的数若是A-F,则x-A+10即是所需要的数字

    • M进制转换为N进制

      可以先将M进制转换为10进制,然后再将10进制转换为N进制

    难题:N位数进制的转换

    经典例题:N诺题库:十进制和二进制

  2. 最大公约数和最小公倍数

    • 最大公约数:

      • 辗转相除法

        int GCD(int a,int b) {
        	if (a < b) {
        		int tmp = a;
        		a = b;
        		b = tmp;
        	}
        	//这里while的条件可以换成a%b!=0,但是最后返回时,就要变成return b;
        	while (a > 0 && b > 0) {
        		int r = a % b;
        		a = b;
        		b = r;
        	}
        	return a;
        }
        
      • 辗转相减法

        int removeGCD(int a, int b) {
        	while (a != b) {
        		if (a > b)a = a - b;
        		if (a < b)b = b - a;
        	}
        	return a;
        }
        
      • 递归

        int dpGCD(int a, int b) {
        	if (a < b) {
        		int tmp = a;
        		a = b;
        		b = tmp;
        	}
        	if(a%b!=0)
        	return dpGCD(b, a%b);
        	else return b;
        }
        
    • 最小公倍数:a*b/gcd(a,b)

      算出最大公约数以后直接用两数乘积除以最大公约数即是最小公倍数

    • 多个数的最大公约数和最小公倍数

      拿三个举例子,先把两个算出来,用两个数的最大公约数和另外一个数来进行计算即可

      最小公倍数也是同理

  3. 质数

    • 判定质数

      #include<stdio.h>
      #include<string.h>
      #include<stdlib.h>
      #include<math.h>
      int isPrime(int n) {
      	if (n <=1) {
      		return 0;
      	}
      	for (int i = 2; i <= sqrt(n); i++) {
      		if (n%i == 0) {
      			return 0;
      		}
      	}
      	return 1;
      }
      int main() {
      	int n;
      	while (scanf_s("%d", &n) != EOF) {
      		if (isPrime(n)) {
      			printf("YES\n");
      		}
      		else {
      			printf("NO\n");
      		}
      	}
      	return 0;
      }
      
    • 一定范围内输出所有质数

      #include<stdio.h>
      #include<string.h>
      #include<stdlib.h>
      #include<math.h>
      //这里巧妙地运用到了常见的flag数组方式,来标记一定范围内的所有数
      #define SWAP(a,b){int t=a;a=b;b=t;}//这里只是一个宏定义
      #define Max 200
      int flag[Max + 1] = { 0 };
      //通常多设置一个单位,就可以实现1-n的数的存放
      void printPrime() {
      	for (int i = 2; i <= sqrt(Max); i++) {
      		if (!flag[i]) {
      			for (int j = 2 * i; j <= Max; j = j + i) {
      				flag[j] = 1;
      			}
      		}
      	}
      	int count = 0;
      	for (int k = 1; k <= Max; k++) {
      		if (!flag[k]) {
      			printf("%-4d ", k);
      			count++;
      			if (count % 5 == 0)
      				printf("\n");
      		}
      	}
      }
      int main() {
      	printPrime();
      	return 0;
      }
      
    • 整数分解(质数幂次的乘积)

      #include<stdio.h>
      #include<stdlib.h>
      #include<string.h>
      #include<math.h>
      char a[1000];
      int formatdevide(int n) {
      	if (n <= 1) {
      		return 0;
      	}
      	int i=0,num = 0;
      	int len = strlen(a);
      	int *b =(int *) malloc(len * sizeof(int));
      	for (int j = 0; j < len; j++) {
      		b[j] = a[j]-'0';
      	}
      	while (n>1) {
      		if (n%b[i] == 0) {
      			num++;
      			n /= b[i];
      		}
      		else {
      			i++;
      		}
      	}
      	return num;
      }
      
      void getPrime(int n) {
      	int *flag = calloc(n+1, sizeof(int));
      	for (int i = 1; i <= n; i++) {
      		flag[i] = 0;
      	}
      	for (int i = 2; i <= sqrt(n); i++) {
      		if (!flag[i]) {
      			for (int j = 2 * i; j <= n; j = j + i) {
      				flag[j] = 1;
      			}
      		}
      	}
      	int num = 0;
      	for (int i = 2; i <= n; i++) {
      		if (!flag[i]) {
      			a[num++] = i+'0';
      		}
      	}
      }
      int main() {
      	int n;
      	while (scanf_s("%d", &n) != EOF) {
      		getPrime(n);
      		int num = formatdevide(n);
      		if (num == 0) {
      			printf("您输入错误,请重新输入\n");
      		}
      		else {
      			printf("%d\n", num);
      		}
      	}
      	return 0;
      }
      
    • 整数的约数个数

      #include<stdio.h>
      #include<stdlib.h>
      #include<string.h>
      #include<math.h>
      char a[1000];
      int formatdevide(int n) {
      	int i = 0, num = 1,clen=0;
      	int len = strlen(a);
      	int *count= (int *)malloc(len * sizeof(int));
      	int *b = (int *)malloc(len * sizeof(int));
      	for (int j = 0; j < len; j++) {
      		b[j] = a[j] - '0';
      	}
      	for (int i = 0; i < len; i++) {
      		int cur=0;
      		while (n%b[i] == 0) {
      			cur++;
      			n /= b[i];
      		}
      		count[clen++] = cur;
      	}
      	for (int i = 0; i < len; i++) {
      		if (count[i]) {
      			num *= count[i] + 1;
      		}
      	}
      	return num;
      }
      
      void getPrime(int n) {
      	int *flag = calloc(n + 1, sizeof(int));
      	for (int i = 1; i <= n; i++) {
      		flag[i] = 0;
      	}
      	for (int i = 2; i <= sqrt(n); i++) {
      		if (!flag[i]) {
      			for (int j = 2 * i; j <= n; j = j + i) {
      				flag[j] = 1;
      			}
      		}
      	}
      	int num = 0;
      	for (int i = 2; i <= n; i++) {
      		if (!flag[i]) {
      			a[num++] = i + '0';
      		}
      	}
      }
      int main() {
      	int n;
      	while (scanf_s("%d", &n) != EOF) {
      		getPrime(n);
      		int num = formatdevide(n);
      		
      			printf("%d\n", num);
      	}
      	return 0;
      }
      

在整数分解过程中,若遇到题目要求过大的数,运行时间明显大于1s,那我们则要选择折中的方法,找出sqrt(x)内的质数即可,因为一个数有质数组成,只有最多有一个大于sqrt(x)的质数,所以我们只要在质数数组遍历完成之后n如果还没有=1,那么肯定存在>sqrt(n)的数存在,则直接加1就好.另外一个优化的地方就是我们也不是非要走到质数数组末尾.只要你当前的n<当前质数数组的值,那么直接退出即可

posted @ 2020-04-21 09:10  coder-sharer  阅读(389)  评论(0)    收藏  举报