第二题:
sin(x)可以看成是数列an=(-1)n-1*x2n-1/(2n-1)!的前n项和。
遇到这种式子,我们可以观察到
二题方法一(a迭代):
思路
当n >= 2 时 :an = -an-1*x2/(2n-2)/(2n-1);
当n = 1 时 :a1 = x;
得知了第n项与第n-1项的关系,而且要求的是每一项的和,所以我们可以让a迭代求和。
#include <stdio.h>
int main()
{
double x;
int n,i;
scanf("%lf%d",&x,&n);
double a = x;
double sum = x;
for(i = 2 ; i <= 2 * n - 1 ; i += 2)
{
temp *= -x * x / i / (i + 1);//进行迭代
sum += temp;
}
printf("%.4lf\n",sum);
return 0;
}
二题方法一(求每一项(室友的方法)):
思路
因为我们知道了an=(-1)n-1*x2n-1/(2n-1)! ,所以我们可以将数列的每一项都求出来。在知道数列的通项公式的时候可以首先想到把每一项都求出来。
#include <stdio.h>
#include <math.h>
int main()
{
double x,sum = 0.0;
int n;
scanf("%lf%d",&x,&n);
double temp = 1.0;//小心temp超出范围哦,阶乘是很大的哦。
int i;
for(i = 1;i <= 2 * n - 1;++i)
{
temp *= i;
}
++n;//因为进入while先执行n--使n减一,所以先++n;
while(n--)
{
sum += pow(-1,n-1)*pow(x,2*n-1)/temp;
temp /= (2*n-1)/(2*n-2);
}
printf("%.4lf\n",sum);
return 0;
}
第五题:
五题解法一(排序):
思路(来自可爱的组员)
因为它要按字符串的长度升序输出,所以我们可以排个序。
#include <stdio.h>
#include <string.h>
int main()
{
int n,i;
char a[100][101];
scanf("%d",&n);
getchar();//scanf后面会有一个/n哦,把它getchar掉
for(i = 0;i < n;i++)
{
gets(a[i]);
}
int j;
for(i = 0;i < n - 1;++i)
{
for(j = i + 1;j < n;++j)
{
if(strlen(a[i]) > strlen(a[j]))
{
char s[101];
strcpy(s,a[j]);
strcpy(a[j],a[i]);
strcpy(a[i],s);
}
}
//这个循环结束出来,a[i]是在i后最短的字符串;
puts(a[i]);
}
puts(a[n-1]);//因为是i==n-1的时候退出了循环,但是a[n-1]还未输出
return 0;
}
五题解法二(标记)
思路
曾经在做字符串去重的时候,我们用过字符串标记法,但是标记了的含义仅仅只代表了字符是否出现过;由这个为基础而拓展,我们可以把标记的数字也赋予含义,先附上代码。
我们是想要让从短到长输出字符串,所以我们可以用一个数组来标记,它的下标代表长度,它的数值代表这个长度的字符串出现的位置:设num[i] = x 那么字符串长度为i的字符串为a[j]
#include<stdio.h>
#include<string.h>
int main()
{
char a[100][101];
int n,i;
scanf("%d",&n);
getchar();//scanf后面会有一个/n哦,把它getchar掉
char num[101];
memset(num,-1,101);
for(i = 0; i < n; i++)
{
gets(a[i]);
num[strlen(a[i])] = i;
}
for(i = 0;i<101;i++)
{
if(num[i] != -1)
{
puts(a[num[i]]);
}
}
return 0;
}
第七题
七题解法一(暴力匹配法):
思路
遇到不匹配即回溯(附图)
从主串和字串的头开始(即i=0;j=0)
发现匹配则让两个都往下挪一个
发现又匹配 再往下挪
哟,不匹配了,怎么办呢,咱们就换一个头开始重新对比
这样,咱们就需要找到原先头对着哪里,所以可以整个k做外层循环来做头即下方代码
#include<stdio.h>
#include<string.h>
int main(void)
{
char a[100],b[30];
gets(a);
gets(b);
int len1=strlen(a);
int len2=strlen(b);
int i,j,k,count=0;
for(k=0;k+len2<=len1;k++)
{
for(i=j,j=0;j<len2;i++,j++)
{
if(a[i] != b[j]) break;
}
if(j == len2 && a[i] == ' ') count++;
}
printf("%d\n",count);
return 0;
}
当然,也可以不需要k,我们可以看出来
之前的头为i-j+1;所以发生不匹配可以让i = i - j +2; j = 0;
这样二层循环可以写成一层循环判断出循环条件为i+len2<=len1即可
七题解法一(KMP算法):
思路
这个的思路是优化了一下上方暴力算法,上方暴力算法是发生不匹配的时候 让i回溯(就是让i回到原先的值),而KMP算法可以让i不回到原先的值,这个算法过几天我会写个算法分析,这个你们可以先看看(有点儿不好理解)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void get_next(char s[],int next[])
{
int i=0;
int j=-1;
next[0]=-1;
int len=strlen(s);
while(i<len-1)
{
if(j==-1||s[i]==s[j])
{
if(s[++i] == s[++j])
{
next[i] = next[j];
}
else
{
next[i] = j;
}
}
else
{
j=next[j];
}
}
}
int KMP(char s1[],char s2[])
{
int i=0;
int j=0;
int count = 0;
int len1=strlen(s1);
int len2=strlen(s2);
int *next = NULL;
next = (int *)malloc((len2)*sizeof(int));
get_next(s2,next);
while(i<len1)
{
if(j == len2)
{
if(s1[i] == ' ')
{
count++;
j = -1;
}
else
{
j = -1;
}
}
if(j == -1 || s1[i] == s2[j])
{
i++;
j++;
}
else
{
j=next[j];
}
}
free(next);
return count;
}
int main()
{
char s1[100];
gets(s1);
char s2[31];
gets(s2);
printf("%d\n",KMP(s1,s2));
return 0;
}
其实这类字符串匹配的有好多种算法,KMP只是其中不好用还慢的一种,但它是我们以后要学的算法,我想有时间再写个Sunday算法(好用还快 )