求最大公共子串(2003)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char* longest_common_substring(char *str1,char *str2)
{
int len1 = strlen(str1);
int len2 = strlen(str2);
int i,j,index1,index2,maxLen=0,num=0;
int start;
//将两个字符串看做两个直尺,固定一个直尺,另外一个从头到尾开始移动,逐一与固定的直尺比较值。
for(i = 0; i < len1; i++)
{
for(j = 0; j < len2; j++)
{
//每移动一次str2就将num重置为0
num=0;
//这里的index1、index2是辅助变量,用于找到在从str1的i处,str2的j处开始,它们的最长子串
index1=i;
index2=j;
while((index1 <= len1-1) && (index2 <= len2-1) && (str1[index1] == str2[index2])){
num++;
index1++;
index2++;
}
if(num > maxLen)//如果num是当前最大匹配的个数,则赋给maxLen,并且在start记下str1最长匹配开始的位置
{
maxLen=num;
start=i;
}
}
}
char *str=(char *)malloc(maxLen + 1);
//从字符串str1的start位置开始,拷贝maxLen个字符到str中,这就是我们找出的最大子串
strncpy(str,str1 + start,maxLen);//也可以改为循环来自己赋值
str[maxLen] = '\0';
printf("最长公共连续子串的长度为:%d\n",maxLen);
return str;
}
int main()
{
char str1[1000],str2[1000];
printf("请输入第一个字符串:");
gets(str1);
printf("请输入第二个字符串:");
gets(str2);
char *str= longest_common_substring(str1,str2);
printf("%s\n",str);
free(str); //记得要free,否则造成内存泄露
system("pause");
return 0;
}
迷宫问题——深度优先搜索(2003)
#include <stdio.h>
#include <stdlib.h>
void visit(int, int);
//由下面的入口和出口坐标可知迷宫的四周都是墙,和平常的迷宫含义不同,注意区别
int maze[9][9] = {{2, 2, 2, 2, 2, 2, 2, 2, 2},
{2, 0, 0, 0, 0, 0, 0, 0, 2},
{2, 0, 2, 2, 0, 2, 2, 0, 2},
{2, 0, 2, 0, 0, 2, 0, 0, 2},
{2, 0, 2, 0, 2, 0, 2, 0, 2},
{2, 0, 0, 0, 0, 0, 2, 0, 2},
{2, 2, 0, 2, 2, 0, 2, 2, 2},
{2, 0, 0, 0, 0, 0, 0, 0, 2},
{2, 2, 2, 2, 2, 2, 2, 2, 2}
};
int startI = 1, startJ = 1; // 入口
int endI = 7, endJ = 7; // 出口
int main(void)
{
int i, j;
printf("显示迷宫: \n");
for(i = 0; i < 9; i++)
{
for(j = 0; j < 9; j++)
if(maze[i][j] == 2)
printf("■");//这个字符代表墙壁,自己可以换
else
printf("□");//这个字符代表空地,自己可以换
printf("\n");
}
visit(startI, startJ);
int qwer;
scanf("%d",&qwer);
return 0;
}
void visit(int i, int j)
{
int m, n;
maze[i][j] = 1;
if(i == endI && j == endJ)
{
printf("\n 显示路径: \n");
for(m = 0; m < 9; m++)
{
for(n = 0; n < 9; n++)
if(maze[m][n] == 2)
printf("■");//这个字符代表墙壁,自己可以换
else if(maze[m][n] == 1)
printf("☆");//这个字符代表路径,自己可以换
else
printf("□");//这个字符代表空地,自己可以换
printf("\n");
}
}
if(maze[i][j+1] == 0) visit(i, j+1);
if(maze[i+1][j] == 0) visit(i+1, j);
if(maze[i][j-1] == 0) visit(i, j-1);
if(maze[i-1][j] == 0) visit(i-1, j);
maze[i][j] = 0;
}
本题的迷宫四周都是墙壁(即数字2),所以visit()
函数递归调用的那几行没有判断是否越界。如果迷宫的四周不一定是墙,则需要改一下那四行,改为如下:
if(j+1<9 && maze[i][j+1] == 0) visit(i, j+1);
if(i+1<9 && maze[i+1][j] == 0) visit(i+1, j);
if(j-1>0 && maze[i][j-1] == 0) visit(i, j-1);
if(i-1>0 && maze[i-1][j] == 0) visit(i-1, j);
整数分解——回溯法(2004)
回忆:
完成的功能是把一个整数 W 分解成不多于 N 个整数的和,且这些整数只能取自数组 b[]
(程序实在想不起来了,只记得程序是用递归完成的,总 共有 5 个空,我认为不难)
若 b[]有序可参考
题目:输入一个正数 n,输出所有和为 n 连续正数序列。
例如输入 15,由于 1+2+3+4+5=4+5+6=7+8=15,所以输出 3 个连续序列 1-5、 4-6 和 7-8。
算法,记 min,max为序列的最值,初始化为 min=1,max=2,当 min+…+max<n 时,max 右移,min+…+max>n 时,min 右移
没有在网上找到类似的题,自己改编为如下题目:
把一个整数 W 分解成不多于 N 个整数的和,且这些整数只能取自有序数组 b[N]
改编之后的题目可以在网上找到解题思路,编写程序如下:
#include<stdio.h>
#define N 5
#define STACK_SIZE 200
int W;
int sum=0;
int a[STACK_SIZE],top=-1;//辅助栈,由于记录分解结果
int b[N]= {1,2,4,8,16}; //题目中的b数组
void division(int i)
{
if(sum==W)
{
printf("%d=",W);
for(int j=0; j<top; j++)
{
printf("%d+",a[j]);
}
printf("%d;\n",a[top]);
return ;//回溯
}
if(sum>W)return;//回溯
for(int j=i; j<N; j++)
{
sum=sum+b[j];
a[++top]=b[j];
division(j);
top--;
sum=sum-b[j];
}
}
int main()
{
scanf("%d",&W);
division(0);
return 0;
}
自守数(2005)
自然数有一类数被成为自守数,意思就是自己和自己相成以后得到的数,尾数不边,例如 25 * 25 = 625。
76 * 76 = 5776。请编写程序,用户输入 M, N, (10 < M < N < 200000 ),求得 M, N 之间的所有自守数并输出。
每 5 个一行
#include <stdio.h>
void automorphic(int begin,int end)
{
int i,n,times,difference;
i = 0;
for(n=begin; n<=end; n++)
{
//得到的times是大于等于n的10的最小次幂,如76可求得times=100
times = 10;
while(n/times>0)
{
times *= 10;
}
//例如76可求得difference=5776-76=5700
difference = n*n - n;
if(difference%times==0)//判断是否为自守数
{
i++;
printf("%d ",n);
if(i%5==0)//用一个整数i记录输出个数,实现每5个一行
{
printf("\n");
}
}
}
}
int main()
{
int m,n;
printf("please input two integer 10<=m<n<200000");
scanf("%d%d",&m,&n);
automorphic(m,n);
return 0;
}
回文数(2006)
判断一个句子是否是回文的。回文是指正序(从左向右)和倒序(从右向左)读都是一样的。
网上做法:(浪费时间,浪费空间)
#include <stdio.h>
#include<string.h>
int main()
{
int j,i,n;
char a[999],b[999];
printf("Please input string: ");
scanf("%s",a); //输入字符串
n=strlen(a); //用strlen函数读取字符串长度
for(i=0,j=n-1; i<n; i++,j--) //循环将字符串a逆序赋值给b
b[j]=a[i];
for(i=0; i<n; i++)
{
if(b[i]!=a[i])
break; //判断是否回文
}
if(i==n) printf("%s是回文字符串\n",a); //如果从第1位到n都相同 则输出回文数
else printf("%s不是回文字符串\n",a);
return 0;
}
我的做法:
int main()
{
int i,j,len,flag=1;
char a[999];
printf("Please input string: ");
scanf("%s",a); //输入字符串
len=strlen(a); //用strlen函数读取字符串长度
for(i=0,j=len-1; i<=j; i++,j--)
{
if(a[i]!=a[j])
{
flag=0;
break;
}
}
if(flag)
{
printf("%s是回文字符串\n",a);
}
else
{
printf("%s不是回文字符串\n",a);
}
return 0;
}
水仙花数(2008)
程序填空:完成判断一个数是否为水仙花数的函数
narcissistic
函数中的第一个循环值得学习,作用为把n的每个数位上的数字放入数组a
#include <stdio.h>
int narcissistic(int n)
{
if(n<100||n>999)return 0;
int temp = n, i = 0, sum = 0, a[3];
while(temp/10>0)
{
a[i++] = temp % 10;
temp /= 10;
}
//上面的循环和下面这句作用为把n的每个数位上的数字放入数组a,要学会迁移
a[i] = temp;
while(i>=0)
{
sum += a[i]*a[i]*a[i];
i--;
}
return sum==n ? 1 : 0;
}
字符串截取(2008)
字符串处理编程题:一字符串第 n 个字符开始的所有字符复制到一新字符串,很简单的程序,但是需要写严谨,考
虑空字符串等等因素
我的做法:
#include <stdio.h>
void copyStrN(char scrStr[],int n,char desStr[])
{
int tmp=n;
for(;scrStr[n]!='\0';n++){
desStr[n-tmp]=scrStr[n];
}
desStr[n-tmp]='\0';
}
int main()
{
char scr[]="Hello SYSU!";
char des[100];
copyStrN(scr,2,des);
printf("%s",des);
return 0;
}
指针输出矩阵下三角(2009)
为一个5*5的二维数组赋值1~25,后输出该右下三角元素
我的做法:
#include <stdio.h>
int main( )
{
int a[5][5],*p=*a;
//这个循环用于初始化
for(int i=0;p<*a+25;i++){
*p++=i+1;
}
p=*a;
for(int j=0;j<5;j++){
for(int k=0;k<5;k++){
//如果行下标和列下标之和大于4,则为下三角的部分
if(j+k>=4){
printf("%3d",*(p+j*5+k));
}else{
printf(" ");
}
}
printf("\n");
}
return 0;
}
字符串转数字(2009)
将字符串转为int型数字可以使用atoi
函数(在<stdlib.h>
中),见下面的例子1;
将int型数字转为字符串可以使用sprintf
函数(在<stdio.h>
中),见下面的例子2;
PS:虽然itoa
也可以将int型数字转为字符串,但它不是标准C语言提供的,所以一些OJ(例如牛客网)不能使用该函数。
例子1(将字符串转为int型数):
#include <stdio.h>
#include <stdlib.h>
int main( )
{
char str[100];
printf("请输入数字串:");
scanf("%s",str);
//atoi函数把字符串转为int,加1是为了展示一下这个是数字
printf("转为数字后加1的结果:");
printf("%d",atoi(str)+1);
return 0;
}
例子2(将int型数字转为字符串):
#include <stdio.h>
#include <string.h>
int main( )
{
char str[100];
int num;
printf("请输入一个数字:");
//注意不要输入超过int范围的数字串
scanf("%d",&num);
sprintf(str,"%d",num);
printf("转为字符串的结果:%s \n长度为:%d",str,strlen(str));
return 0;
}
求字符串的子串个数(2010)
#include <stdio.h>
int subStrNum(char str[],char subStr[])
{
int count = 0,i = 0, j, k;
while(str[i]!='\0')
{
k = i;
j = 0;
while(subStr[j]!='\0')
{
if(str[k]==subStr[j])
{
k++;
j++;
}
else
{
break;
}
}
if(subStr[j]=='\0')
{
//从匹配到的子串下一位开始继续匹配
i = k;
count++;
}
else
{
i++;
}
}
return count;
}
int main(){
char str[]="123661230609123";
char subStr[]="123";
int num=subStrNum(str,subStr);
printf("%d",num);
return 0;
}
圈型矩阵输出(2010)
程序功能是输出一个这样的矩阵:
111111111
122222221
123333321
123444321
123454321
123444321
123333321
122222221
我的解法(参考了叠箩筐那题的思路,见后文):
#include<stdio.h>
int main()
{
int n, m[20][20];
printf("请输入1至17的奇数:");//输入太大的数得到的中间数字会超过9导致不整齐
scanf("%d",&n);
int cen=n/2;//中心位置的行、列下标
int cenNum=cen+1;//中心数字
m[cen][cen]=cenNum--;
for(int level=1; level<=cen; level++,cenNum--)
{
//本圈的上面的边
for(int i=cen-level,j=cen-level; j<=cen+level; j++)
{
m[i][j]=cenNum;
}
//本圈的下面的边
for(int i=cen+level,j=cen-level; j<=cen+level; j++)
{
m[i][j]=cenNum;
}
//本圈的左边的边
for(int i=cen-level,j=cen-level; i<=cen+level; i++)
{
m[i][j]=cenNum;
}
//本圈的右边的边
for(int i=cen-level,j=cen+level; i<=cen+level; i++)
{
m[i][j]=cenNum;
}
}
//输出矩阵
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
printf("%d",m[i][j]);
}
printf("\n");
}
return 0 ;
}
类似的经典题(叠箩筐):
Problem Description
需要的时候,就把一个个大小差一圈的筐叠上去,使得从上往下看时,边筐花色交错。这个工作现在要让计算机来完成,得看你的了。
Input
输入是一个个的三元组,分别是,外筐尺寸n(n为满足0< n<80的奇整数),中心花色字符,外筐花色字符,后二者都为ASCII可见字符;
Output
输出叠在一起的筐图案,中心花色与外筐花色字符从内层起交错相叠,多筐相叠时,最外筐的角总是被打磨掉。叠筐与叠筐之间应有一行间隔。
Sample Input
11 B A
5 @ W
Sample Output
AAAAAAAAA
ABBBBBBBBBA
ABAAAAAAABA
ABABBBBBABA
ABABAAABABA
ABABABABABA
ABABAAABABA
ABABBBBBABA
ABAAAAAAABA
ABBBBBBBBBA
AAAAAAAAA
@@@
@WWW@
@W@W@
@WWW@
@@@
本题参考答案(思路见注释):
#include<stdio.h>
int main()
{
int i, d, k, a, j, flag=0;
char inner, outer, m[100][100]= {0},ch;//m为二维数组,先放好字符,再输出
while(scanf("%d %c %c",&a, &inner, &outer) != EOF)
{
if(flag == 1)
{
printf("\n");
}
flag = 1;
if(a == 1)
{
printf("%c\n",inner);
continue;
}
//找到中心位置,刚好是m[a/2][a/2],放入中心字符;
d = a/2;
m[d][d] = inner;
//从中心向外边一圈圈放字符;注意要找到边界(如下面的几个for语句就是这个意思)
for(k = 1; k <= d; k++)
{
//一共要放d圈,第奇数圈为外字符outer,第偶数圈为内字符inner
ch = k%2==1 ? outer : inner;
//下面的四个循环的变量i和j为相对于中心的偏移量,即利用了中心位置是 (d, d) 的这个信息
for(i = d-k, j = d-k; i <= d+k; i++)
{
m[i][j] = ch;
}
for(i = d+k, j = d-k; j <= d+k; j++)
{
m[i][j] = ch;
}
for(i = d+k, j = d+k; i >= d-k; i--)
{
m[i][j] = ch;
}
for(i = d-k, j = d+k; j >= d-k; j--)
{
m[i][j] = ch;
}
}
//最后将边框四角置为空格,覆盖掉之前的字符
m[0][0] = ' ';
m[a-1][0] = ' ';
m[a-1][a-1] = ' ';
m[0][a-1] = ' ';
//最后简单的输出二维数组即可
for(i = 0; i < a; i++)
{
for(j = 0; j < a; j++)
{
printf("%c",m[i][j]);
}
printf("\n");
}
}
return 0 ;
}
判断是否为子串(2011)
#include <stdio.h>
#include <string.h>
/*判断subs是否为str的子串*/
int isSubString(char *subs, char *str){
int len1=strlen(str);
int len2=strlen(subs);
int index,i,j;
for(i=0;i<len1;i++){
index=i;
for(j=0;j<len2&&index<len1;j++,index++){
if(str[index]!=subs[j])break;
}
if(subs[j]=='\0'){
return 1;
}
}
return 0;
}
字符串重排序字符(2011)
一个只有字母和数字的字符串,变成全部数字都在左边,全部字母都在右边的字符串。
我的代码(《王道》上学的):
#include <stdio.h>
#include <string.h>
int isNumber(char c){//<ctype.h>中的isdigit()可以代替
return c>='0'&&c<='9';
}
int isLetter(char c){//<ctype.h>中的isalpha()可以代替
return (c>='a'&&c<='z')||(c>='A'&&c<='Z');
}
int main()
{
char str[100];
scanf("%s",str);
int len=strlen(str);
int i=0,j=len-1;
while(i<=j){
while(i<=j&&isNumber(str[i])) i++;
while(i<=j&&isLetter(str[j])) j--;
if(i<=j){
char tmp=str[i];
str[i]=str[j];
str[j]=tmp;
}
i++;j--;
}
printf("%s",str);
return 0 ;
}
读文件,排序,写到另一个文件(2011)
设计一个程序,从in.txt读入数据,对每一行的数字都单独按从大到小的顺序排序,将结果输出到out.txt。每一行的数字第一个字符是数字标志,每个数字之间用空格隔开。如:
读入:5 10 -20 2000 36 -100
输出:2000 36 10 -20 -100(注意5只是个开始标志)。
#include <stdio.h>
#include <stdlib.h>
int cmp(const void *a,const void *b){
return *(int *)b-*(int *)a;
}
int main(){
/*打开文件*/
FILE *frp=fopen("D:\\in.txt","r");//考试时写"int.txt"
FILE *fwp=fopen("D:\\out.txt","w");//考试时写"out.txt"
if(frp==NULL||fwp==NULL){
printf("cannot open file");
exit(1);
}
/*处理文件*/
int len;
int isFirstLine=1;
while(!feof(frp)){
//处理回车问题
if(isFirstLine){
isFirstLine=0;
}else{//不是第一行则先回车
fprintf(fwp,"\n");
}
len=0;
fscanf(frp,"%d",&len);
int *arr=(int *)malloc(sizeof(int)*len);
for(int i=0;i<len;i++){
fscanf(frp,"%d",arr+i);
}
//排序
qsort(arr,len,sizeof(int),cmp);
//输出
int k=0;
for(;k<len-1;k++){
fprintf(fwp,"%d ",arr[k]);
}
fprintf(fwp,"%d",arr[k]);//每行最后一个不需要空格
free(arr);
}
/*关闭文件*/
fclose(frp);
fclose(fwp);
return 0;
}
求数字串的最大值顺序(2012)
给定一个数字串。求前 N 个数字组成的数字最大值
#include <stdio.h>
#include <stdlib.h>
int cmp(const void *a,const void *b){
//逆序排序,所以是b-a
return *(char *)b-*(char *)a;
}
int main()
{
char str[100];
int N;
scanf("%s",str);
scanf("%d",&N);
qsort(str,N,sizeof(str[0]),cmp);
str[N]='\0';
int maxNum=atoi(str);//字符串转数字
printf("%d",maxNum);
return 0 ;
}
字符串大写转小写(2012)
似乎是把大写转变小写,不过没有那简单,这一题比较难
当做是大写转小写的题目
#include <stdio.h>
int main()
{
char str[100];
scanf("%s",str);
for(int i=0;str[i]!='\0';i++){
if(str[i]>='A'&&str[i]<='Z'){
str[i]+=32;//大写字母与小写字母的ASCII相差32
}
}
printf("%s",str);
return 0 ;
}
分隔符打印字符串(2012)
两个字符串,用一个字符串里面的字符作为分隔符,打印另外一个字符串。一遇到分隔符,就回车。
例如 S1:abcdefg ,S2:bdf ,把 S2 作为分隔符,打印 S1.
结果是:
a
c
e
g
#include <stdio.h>
void printStr(char *str,char *subStr)
{
int flag =0 ;
for(int i=0;str[i]!='\0';i++){
for(int j=0;subStr[j]!='\0';j++){
if(str[i]==subStr[j]){
flag=1;
break;
}
}
if(flag){
printf("\n");
flag=0;
}else{
printf("%c",str[i]);
}
}
}
int main()
{
char str[]="1*2@3*4*5";
printStr(str,"*@");
return 0;
}
删除字符串中的数字(2014)
我的代码:
#include <iostream>
using namespace std;
void removeDigit(char str[]){
int num=0,i=0;
for(;str[i];i++){
if(str[i]>='0'&&str[i]<='9'){
num++;
}else{
str[i-num]=str[i];
}
}
str[i-num]='\0';
}
int main(){
char str[]="123adf4ad1234fasdf2134";
removeDigit(str);
cout<<str;
return 0;
}
文件操作(2016)
从文件data.txt输入数据,然后输出到文件result.txt。把data.txt的文件内容每行当成一组,然后把每组最大的数字和最小的数字输出
data.txt
123 4 10
21 23 44 8 100
result.txt
123 4
100 8
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 100
int main(){
//打开文件
FILE *frp = fopen("D:\\in.txt", "r");
FILE *fwp = fopen("D:\\out.txt","w");
if(frp==NULL||fwp==NULL){
printf("cannot open file!\n");
exit(1);
}
//读取文件并打印
char str[N];
while (!feof(frp)){
fgets (str, N, frp);
char *p = strtok(str, " \n");//空格与回车都作为分隔符
int tmp=atoi(p);
int min=tmp,max=tmp;
while((p = strtok(NULL, " \n"))!=NULL) {
tmp=atoi(p);
if(tmp<min)min=tmp;
if(tmp>max)max=tmp;
}
fprintf(fwp,"%d %d\n",max,min);
}
//关闭文件
fclose(frp);
fclose(fwp);
return 0;
}
文件操作(2018)
用题目要求的三个函数(分别是:排序,输入,输出)实现功能:从文件 data.txt 中读取学生成绩,并将他们按姓名首字母排序,写入student.txt 中
个人推测data.txt每行格式为姓名+空格+成绩,即:
Liu 88
Zhang 77
Xie 100
Sun 99
则代码如下:
#include <stdio.h>
#include <stdlib.h>
#define N 100
typedef struct STU{
char name[N];
double point;
}STU;
/*从filename文件读入学生信息到ss数组,返回读入的学生信息数*/
int fileInput(char *filename, STU *ss){
FILE *frp = fopen(filename, "r");
if(frp==NULL){
printf("cannot open file!\n");
exit(1);
}
int i=0;
while(!feof(frp)){
fscanf(frp,"%s %lf",ss[i].name,&ss[i].point);//记得double的格式控制符为 %lf
i++;
}
//关闭文件
fclose(frp);
return i;
}
/*对ss数组按照姓名首字母排序,num为学生个数*/
void sortByName(STU *ss,int num){
for(int i=0;i<num-1;i++){//记忆:0和num-1就是要排序的下标范围
for(int j=i+1;j<num;j++){//记忆:比上一个循环各加一
if(ss[i].name[0]>ss[j].name[0]){
STU tmp=ss[i];
ss[i]=ss[j];
ss[j]=tmp;
}
}
}
}
/*输出ss的学生信息到filename文件,num为学生个数*/
void fileOutput(char *filename,STU *ss,int num){
FILE *fwp = fopen(filename, "w");
if(fwp==NULL){
printf("cannot open file!\n");
exit(1);
}
for(int i=0;i<num;i++){
fprintf(fwp,"%s %lf\n",ss[i].name,ss[i].point);//记得double的格式控制符为 %lf
}
fclose(fwp);
}
int main(){
//打开文件
char *inFile="D:\\in.txt";
char *outFile="D:\\out.txt";
STU ss[N];
//输入
int num=fileInput(inFile,ss);
//排序
sortByName(ss,num);
//输出
fileOutput(outFile,ss,num);
return 0;
}