1、输出最长的名字
一个班级中有n个学生,每个学生有一个名字。班主任希望知道学生中名字最长(名字中的一个空格长度计为1)的学生是谁。
输入格式
程序接受的输入的第一行是一个整数n,表示学生的总数。之后的n行,每行会接受一个学生的名字(可能有空格)。学生的名字不超过100个字符。
输出格式
输出n位学生中最长的学生名字(如果有多个名字一样长的学生,输出第一个。
样例输入
3
steve Jobs
Masunny
Fei
样例输出
steve Jobs
#include <stdio.h>
#include <string.h>
int main()
{
int n;
scanf("%d\n", &n);
char arr[n][100];
for(int i = 0;i < n;i++)
{
for(int j = 0;j < 100;j++)
{
scanf("%c",&arr[i][j]);
if(arr[i][j]=='\n')
{
break;
}
}
}
for(int k=0;k<1;k++)
{
for(int p=0;p<n-1;p++)
{
if(strlen(arr[0])<strlen(arr[p+1]))
{
strcpy(arr[0],arr[p+1]);
}
}
}
for(int i =0;i<strlen(arr[0]);i++)
{
if(arr[0][i] == '\n')
{
break;
}
else
{
printf("%c",arr[0][i]);
}
}
return 0;
}
2、新哈希函数
一个哈希函数将一个长度为k的字符串转成长度为32的字符串。这个哈希函数f的设计如下:
·声明一个长度为32的数组arr,并将其中元素全部初始化为0。
·取出每一位的ASCIl值,将长度为k的字符串中第i位的ASCIl码加入到 arr[i % 32] 中 ( 1 ≤ i ≤ k )。
·声明一个长度为32的数组bits,令bits[j]为arr[31 - j ]与 arr[ j ] <<1 的值进行了按位异或运算后得到的结果( 0 ≤ j ≤ 31)。
·计算出 bits[ j ] % 85 + 34并将该十进制数在ASCIl码中对应的字符输出到结果字符串的第 j+1位( 0 ≤ j ≤ 31) 。
实现一个程序,当输入一个字符串s后,输出哈希图数的结果f(s)。
输入格式
输入为一行,包括一个长度为k的字符串(32< k < 500),这个字符串由大写字母、小写字母和数字组成(不含空格)。
输出格式
输出为一行,为一个长度为32的字符串哈希结果
样例输入
123456789012345678981234567890123
样例输出
"p*+,)&'ebst*+,)&'ebst*+,)&'eb&r
#include <stdio.h>
int main()
{
int arr[32] = {0};
int bits[32];
int j, k;
char m;
char string[501];
scanf("%s", string);
k = strlen(string);
for (j = 0; j < k; j++){
arr[(j + 1) % 32] += string[j];
}
for (j = 0; j < 32; j++){
bits[j] = arr[31 - j] ^ (arr[j] << 1);
}
for (j = 0; j < 32; j++){
printf("%c", bits[j] % 85 + 34);
}
return 0;
}
3、权限的修改
在Linux操作系统中文件的权限可以通过rwx 的方式来表示,r表示可读,w表示可写,x表示可执行。
在操作系统实现这个功能时,采用的方式是按位存储的。当不给任何权限时,存储表现为三个二进制位0,如果可读则第一位会变成1、如果可写则第二位会变成1、如果可执行则第三位会变成1。例如
·如果可读、可写、可运行,就表示为二进制的111,转换成十进制就是7。
·如果可读、可写、不可运行,就表示为二进制的110,转换成十进制就是6。
·如果可读、不可写、可运行,就表示为二进制的101,转换成十进制就是5。
在这题中,会得到文件当前的权限和希望添加或删除的权限(如果已经对存在/不存在的权限添加/删除则不做改变)。需要输出最终改变后的权限的十进制描述。
输入格式
输入第一行是当前的文件权限,用r、w、x的字母中的一个或多个来表示( r,w,x 不会重复)。之后每一行会以+或·开头;如果以+开头,则表示添加一个权限,如果-开头,则表示删除一个权限。
输出格式
将修改后的权限以十进制数字的方式输出出来。
样例输入1
rw
+x
样例输出1
7
#include <stdio.h>
#include <string.h>
int main() {
char jur[3];
char ar[2];
int num = 0;
scanf("%s", jur);
//先对当前的权限进行转换成数值。相当于加权限=加法运算:r=4,w=2,x=1
for(int i = 0; i < 3; i++){
if(jur[i] == 'r'){
num = num + 4;
}else if(jur[i] == 'w'){
num = num + 2;
}else if(jur[i] == 'x'){
num = num + 1;
}
}
//进行权限修改的部分
//加权限就是加法运算
//减权限,这里用到的是对二进制的第几位进行置零的操作
while(scanf("%s", ar) != EOF){
if(ar[0] == '+'){ //加权限
if(ar[1] =='r'){
num = num + 4;
}else if(ar[1] == 'w'){
num = num + 2;
}else if(ar[1] == 'x'){
num = num + 1;
}
}else if(ar[0] == '-'){ //减权限
if(ar[1] == 'r'){
num &= ~(1 << 2);
}else if(ar[1] == 'w'){
num &= ~(1 << 1);
}else if(ar[1] == 'x'){
num &= ~(1 << 0);
}
}
getchar();
}
printf("%d\n", num);
return 0;
}
4、欧几里得算法
求最大公因式
#include <stdio.h>
int gcd(int a, int b)
{
return (b ? gcd(b, a % b): a);
}
int main()
{
int a, b;
while (scanf("%d%d", &a,&b))
{
printf("gcd(%d,%d)= %din" , a, b, gcd(a, b));
}
return 0;
}
拓展的欧几里得算法:
#include <stdio.h>
int ex_gcd(int a, int b, int *x,int *y)
{
if (!b)
{
*x = 1,*y = 0;
return a;
}
int xx, yy, ret = ex_gcd(b, a % b, &xx,&yy );
*x = yy;
*y = xx - a / b * yy ;
return ret;
}
int main()
{
int a, b, x, y;
while (scanf("%d%d", &a,&b) != EOF)
{
printf("ex_gcd(%d,%d) = %d\n", a,b, ex_gcd(a,b,&x,&y));
printf("%d * %d+ %d* %d= %d\n", a,x, b, y, a * x + b * y);
}
return 0;
}
5、素数筛代码
描述:
1、标记一个范围内的数字是否是合数,没有被标记的则为素数
2、算法的空间复杂度为O(N),时间复杂度为o(N * loglogN)
3、总体思想是用素数去标记掉不是素数的数字,例如 i 是素数,那么2i、3i、4*i……就都不是素数
步骤:
1、用prime[ i ]来标记 i 是否是合数
2、标记为1的数字为合数,否则为素数
3、第一次知道2是素数,则将2的倍数标记为1
4、向后找到第一个没有被标记的数字 i
5、将 i 的倍数全部标记为合数
6、重复4–6步,直到标记完范围内的所有数字
#include <stdio.h>
#include <inttypes.h>
#define MAX_RANGE 10000 //求出10000以内的素数
int prime[MAX_RANGE + 5]={[0}; //初始值为0,代表没有被标记成合数
int main()
{
for (int i = 2; i*i<= MAX_RANGE; i++)
{
if (!prime[i]) // i没有被标记过,说明i是素致
{
for (int j=2*i; j <= MAX_RANGE; j += i) //枚举i的倍数
{
prime[j]=1; //将i的倍数标记为1,说明其是合数
}
}
}
int n;
while (scanf("%d",&n) != EOF)
{
printf("%s\n", prime[n] == 0 ? "YES" :"NO"); //如果n是素敢,输出YES,香则输出NO
}
return 0;
}
#include <stdio.h>
#define max_n 100
int prime[max_n + 5]={0};
void init()
{
for (int i =2; i<=max_n;i++)
{
if (prime[i]) continue; //?
prime[++prime[0]] = i; //?
for(int j = i*i;j<=max_n;j += i)
{
prime[j] = 1;
}
}
return ;
}
int main()
{
init();
for (int i = 1; i <= prime[0]; i++)
{
printf("%d\n", prime[i]);
}
printf("prime[0] = %d\n",prime[0]);
return 0;
}
输出:
prime[++prime[0]] = i;
等价于
int cnt;
cnt = cnt + 1;
prime[cnt] = i;
6、用异或交换两个数
#include <stdio.h>
int main()
{
int a = 7, b = 3, c;
a += 7;
int *p = &a;
(*p)--;
printf("a = %d, b = %d\n", a, b);
a ^= b; //等价于 int temp = a;
b ^= a; // a = b;
a ^= b; // b = temp;
printf( "swap : a = d , b = %d \n", a, b);
return 0;
}
异或存在的一些特点:
a ^ b=c也可以表示为a ^ c=b、b ^ c=a
在此处使用三个异或完成交换可以这样理解:
a ^= b 为 a = a ^ b 可视为 a’ = a ^ b
b ^= a 为 b = b ^ a 也就是 b = b ^ a’ = b ^ a ^ b = a ,此时已将a的值赋给b了
同理a ^= b 为 a = a ^ b 也就是 a = a ^ b = a ^ b ^ a = b ,此时已将b的值赋给a了
7、循环读入
方法一:
#include <stdio.h>
int main()
{
int n;
while(~scanf("%d",&n))
{
printf("n=%d\n",n);
}
return 0;
}
方法二:
#include <stdio.h>
int main()
{
int n;
while((scanf("%d",&n)) != EOF)
{
printf("n=%d\n",n);
}
return 0;
}
等价于
#include <stdio.h>
int main()
{
int n;
while((scanf("%d",&n)) != -1)
{
printf("n=%d\n",n);
}
return 0;
}
8、回文数字
#include <stdio.h>
int rev_num(int n, int base)
{
if (n < 0) return 0;
int x = n,temp = 0;
while (x)
{
temp = temp * base + x % base;
x /= base;
}
return temp -= n;
}
int main()
{
int n;
scanf("%d"",&n);
printf("%s\n", rev_num(n,10)?"YES":"NO" ); // 10为base的实参
int x = n,digit = 0;
do // 判断输入值是几位数
{
x /= 10;
digit += 1;
}while (x);
printf("%d has %d digits!\n", n, digit);
return 0;
}
【 rev_num ( n ) ? " YES " : " NO "】意思是:如果rev_num ( n ) 的返回值为1则输出yes,为0则输出no
翻转回文数字并将值存到temp中:【 temp = temp * 10 + x % 10;x /= 10;】可以举个例子123翻转尝试一下
9、高效代码
(1)
#define likely (x) __builtin_expect ( !!(x) , 1 ) //likely 代表x经常成立
#define unlikely (x) __builtin_expect ( !!(x) , 0 ) //unlikely代表x不经常成立
(2)
想要输出几个数字1 2 3 4 5,第一个数字前面没有空格,后面数字前面都有空格
for(int i=0,i<5,i++)
{
if(i) // 看这里
{
printf(" ");
}
printf("%d",i);
}
if ( i != 0) printf(" ");
//等价于
if ( i ) printf(" "); //if(表达式)表达式的值为1后面的程序执行,若为0则不执行。
//又等价于
i && printf(" ");
//还等价于
i == 0 || printf(" "); //逻辑与运算中i值不为0才可以进行下面,逻辑或前面已成立则不执行后面
if(表达式)表达式的值为1后面的程序执行,若为0则不执行。
逻辑与运算中i值不为0才可以进行下面,逻辑或前面已成立则不执行后面
(3)
#include<stdio.h>
int main()
{
int a = 0,b = 0;
if((a++)&&(b++))
{
printf("true\n");
}
else
{
printf("false\n");
}
printf("a=%d,b=%d\n",a,b);
return 0;
}
运行结果为false以及a=1,b=0
在逻辑与的运算中存在一种短路原则,if判断初a++是先赋值后加,因此先赋值a=0,则逻辑与后面不看此结果的值都为0了,因此输出false。后面打印时,a已经赋值操作完毕,因此后加输出为1,而b在前面就没有被执行,因此输出仍为原始值0
(4)
#include<stdio.h>
#include<stdlib.h> // rand(),srand()所在头文件
#include<time.h> // time(0)所在头文件
int main()
{
int n, cnt = 0;
srand(time(0)); // 让每次产生的随机数都不一样
scanf("%d",&n);
for (int i = 0; i < n; i++)
{
int val = rand() % 100; // 产生随机数
cnt += (val & 1); // 统计奇数或偶数的个数
i && printf(" ");
printf(""%d", val);
}
printf("\n");
printf( "odd num : %din", cnt);
return 0;
}
// 统计奇数或偶数的个数
if(val % 2) cnt += 1;
//等价于
if(val & 1) cnt += 1;
//又等价于
cnt += (val & 1);
10、输出一定数量的偶数
给定一个起始值begin,及一个整数n,输出begin之后(可包含begin)的n个偶数
输入格式:
一行,两个整数,第一个整数对应着起始数字begin,第二个整数对应着将要输出的偶数的个数。
输出格式:
若begin为奇数,则从begin + 1输出,共输出n个偶数;
若begin为偶数,则从begin开始输出,输出n个偶数;
若begin为负数,则从第一个偶数开始输出;
每个偶数输出占一行,0为第一个偶数
#include<stdio.h>
int main()
{
int begin,n;
scanf("%d %d",&begin,&n);
if(begin < 0 ) begin = 0;
begin += ( begin & 1); //begin & 1 等价于 begin % 2
while(n--)
{
printf("%d\n",begin);
begin += 2;
}
return 0;
}