做题总结(一)


(还有涉及到还涉及到二分查找、定义结构体类型变量的方法、 进制转换、错排、数组模拟等,稍后我会专门为这些整理)

一、以字符串的例题强调知识点

1.字符串每个的首字母变成大写

感谢 yzx 大佬
分析

  • 如何输入多组含空格的字符串
  • 如何确定每个单词的首字母

代码中涉及到的点

  • while(gets(str)!=EOF) 如果这样写, 会输出超限,gets读取到EOF会返回nall, 和scanf不同
  • while(scanf("%s", str) != EOF) 读到空格就会结束,且这种字符串的输入不需要 &
  • 除第一个单词外每个单词的第一个字母前都有一个空格
  • 在ASCII码中,小写字母减去相应大写字母 = 32,
    例如:a - A = 32

自己的小破代码

#include <stdio.h>
int i, len;
char str[22000];
int main(void){
    
    
    while(gets(str)){
    
    //输入多组字符串样例这样写即可
        len = strlen(str);
        str[0] = str[0] - 32;
        for(i = 1; i < len; i++){
    
    
            if(i < len -1 && str[i] == ' ' && str[i+1] != ' '){
    
    
                str[i+1] = str[i+1] - 32; 
      //从前往后,莫得特殊情况
      //注意这里是 i+1, 下面不用写 else if(i== len-1)重复了
            }

        }
        printf("%s\n",str);
    }
    return 0;
}

2.字符串的部分改变

  • 题目简单描述: 当出现超过3个连续的 6 时, 需替换成 “9”, 如果
    有超过 9 个连续的 6 时, 则将这串连续的 6 替换成 “hun yuan zhb”.

分析

  • 开始不成熟想法: 尝试着填入一个新数组,但该新数组的大小和原按字符串大小可能不一样了, 没有想到如何直接操作,难免涉及到 下列思路。
  • 我们可以直接输出, 涉及到
    计录连续“6”的个数,
    if分支等基础知识的应用
#include <stdio.h>
int n, i, j, sum, len;
char str[2000];
int main(void){
    
    
    gets(str);
    len = strlen(str);
    for(i=0; i<len; i++){
    
    
        if(str[i] == '6'){
    
    
            sum++;
        }
        //记录连续“6”的个数
        /*接下来讨论连续6的个数的不同情况*/
        else if(sum <= 3 && str[i+1] != '6'){
    
    
            for(j=0; j< sum; j++){
    
      
                printf("6");
                sum = 0;  //记得 sum = 0
            }
        }
        else if(sum > 3 && sum <= 9 && str[i+1] != '6'){
    
    
            printf("9");
            sum = 0;
        }
        else if(sum > 9 && str[i+1] != '6'){
    
    
            printf("hun yuan zhb");
            sum = 0;
        }
        else if(str[i] != '6'){
    
    
            printf("%c",str[i]);
        }
    }
    return 0;
}

3.统计汉字个数

分析
汉字是由两个小于0的字符组成,可以直接 用strlen 函数即可,在统计结果的时候就要将count除以2 即可

#include<stdio.h>
#include <string.h>
char str[900];
int count;
int main(void)
{
    
    	
	gets(str);
	count = strlen(str);
	printf("%d", count / 2);
	return 0;
}

二、峰值原理

感谢 ysq 大佬

简单描述

在一天内可以进行多次交易(多次买卖一支股票),xxx必须在再次购买前出售掉之前的股票,求能获得的最大利润。主要就是考的峰值原理,这里也只是感觉峰值原理的应用,敲一下核心代码

峰值图

在这里插入图片描述

核心代码

//直接遍历
if(arr[i] < arr[i+1]){
    
    
    sum += arr[i+1] - arr[i]
}

三、求n个数的最小公倍数

分析
先求两个数的最大公约数------辗转相除法
再求这两个数的最小公倍数,拿该数和其他数再求

#include <stdio.h>
int i, x, a, n, j;
int arr[100010];

int sy(int a, int b){
    
      //辗转相除法
    int  r;
    while(b != 0){
    
    
        r = a % b;
        a = b;
        b = r;
    }
    return a;
}
int main( void ){
    
    
    while(scanf("%d",&n)!=EOF){
    
    
        i = 0;
        while(n--){
    
    
            scanf("%d",&arr[i]);
            i++;
        }
        a = arr[0];//a 记录前几个的最小公倍数
        for(j = 1; j < i; j++){
    
    
                a =   a   /    sy(a, arr[j])   *    arr[j];
        }  
        //先除以最小公约数,再乘另一个数,减少溢出的可能
        printf("%d\n", a);
    }
    return 0;
}

另赠一个细节问题: 求 a 的 b 次方的后三位组成的数字

while(b--)
     {
    
    
        s=s*n;//如果先求出n的m次方,这个数可能会很大,导致溢出,所以每次两个数相乘后就对1000取余
        s=s%1000;//因为是求后三位所以取余1000,其他以此类推
     }
printf("%d\n", sum);

注意题目的说法: 该数是正数, 要考虑浮点数

四、涉及到数学几何问题

1.给出多边形的坐标(整数),求面积

分析
该处只想记录一个公式(具体怎么推导,不晓得啊)

for(i=0; i < j-1; i++){
    
    
     sum += abs(arr[i].x * arr[i+1].y - arr[i+1].x * arr[i].y);
     //可以简单这样记 x1 * y2 - x2 * y1
}
     sum += abs(arr[j-1].x * arr[0].y - arr[0].x * arr[j-1].y);
     sum = 1.0 * sum / 2;  //sum 定义成double类型的

2.输入两矩形对角线坐标,输出交叉部分面积

如没有相交部分,输出0.00即可
分析
1.没有告诉我们输入的是矩形的哪条对角线,需要转化统一。
2.判断相交时坐标特点
在这里插入图片描述
在这里插入图片描述

#include <stdio.h>
double a1, b1, a2, b2, a3, b3, a4, b4, x1, y1, x2, y2;
int main(void){
    
    
    while(scanf("%lf %lf %lf %lf %lf %lf %lf %lf", &a1, &b1, &a2, &b2, &a3, &b3, &a4, &b4) != EOF){
    
    

//统一:x1,y1为左下角, x2, y2右上角,,
//需要判断大小关系,转化一下即可。
        if(a1 > a2){
    
    
            x1 = a1;
            a1 = a2;
            a2 = x1;
        }
        if(b1 > b2){
    
    
            y1 = b1;
            b1 = b2;
            b2 = y1;
        }
        if(a3 > a4){
    
    
            x1 = a3;
            a3 = a4;
            a4 = x1;
        }
        if(b3 > b4){
    
    
            y1 = b3;
            b3 = b4;
            b4 = y1;
        }
        //求相交图形的坐标
        x1 = a1 > a3 ? a1 : a3;
        y1 = b1 > b3 ? b1 : b3;
        x2 = a2 > a4 ? a4 : a2;
        y2 = b2 > b4 ? b4 : b2;
        if(x1 < x2 && y1 < y2){
    
    
            printf("%.2f\n", (x2 - x1) * (y2 - y1));
        }
        else{
    
    
            printf("0.00\n");
        }
    }
    return 0;
}

3.无限的路

(看图形,观察规律)
在这里插入图片描述

样例
2
0 0 0 1
0 0 1 0
/*输出
1.000
2.414*/

规律
横纵坐标相加,得出的就是最高点的坐标,而且代表着是第几条倾角为145度的斜线,相应代表这里有几个根号二长度。

#include <stdio.h>
#include <math.h>
int  x, y, k, l, n, p;
double sum1, sum2;
int main(void){
    
    
    scanf("%d", &n);
    while(n--){
    
    
        sum1 = 0.0;
        sum2 = 0.0;
        scanf("%d %d %d %d", &x, &y, &k, &l);
        p = x + y;
        while(p--){
    
        
            sum1 += (sqrt(2) * p);
            sum1 += sqrt(p * p + (p+1) *(p+1)); //该处加的是两点间的直线段
          
        }
        sum1 += (sqrt(2) * x);  //算出所在边的折线的长度
        p = k + l;
        while(p--){
    
    
            sum2 += (sqrt(2) * p);
            sum2 += (sqrt((p+1)*(p+1) + p * p));
        }
        sum2 += (sqrt(2) * k);
        printf("%.3f\n", fabs(sum1 - sum2));  //注意这里是小数,用fabs
    }
    return 0;
}

4.直线、折线分割平面

主要记住两个公式

/* 直线分割平面*/  设有n条直线
围成的封闭的区域:   M1= 1+2+3+....+n-2  ;
非封闭区域:    M2= 2*n;
M = M1+M2
/*折线*/  设有n 条
两条直线的一个端点相交,就变成了一条折线,被分割的区域减少2;
//n条折线分割的区域数M2,只需求出2n条直线分割区域数目为M, 则M-2*n=M2;

五、判断两个数是否相等

分析
考虑到数可能非常大,超过long long范围,double精度也可能满足不了时,我们采用字符串比较strcmp 函数
. 的ASCII码小于任何一个数字
思考
5.0和5==> 所以我们要去掉小数点后的0
方法一: 装入一个新数组

#include<stdio.h>
#include<string.h>
char a[100000],b[100000],c[100000],d[100000];
int i,k,len1,len2;
int main()
{
    
    
    while(~scanf("%s  %s",&a,&b))
    {
    
    
        len1=strlen(a);
        len2=strlen(b);
        k=len1;
        for(i=len1-1;a[i]=='0';i--);  
        
     /*i是小数点后第一个0的位置,或者没有小数点,
     第一个0的位置    5000, 5.000*/
        if(strstr(a,".")==0)  
        //当输入的没有小数点时,会改变i的值, 不会改变数的大小
        {
    
    
            i=len1-1;
        }
        for(k=0;k<=i;k++)
            c[k]=a[k];  //把第一个数去小数点后0后转到c中
        if(c[k-1]=='.')
            c[k-1]='\0';
        else
            c[k]='\0';  //设置数组的最后一位

        k=len2;
        for(i=len2-1;b[i]=='0';i--);
        if(strstr(b,".")==0)
        {
    
    
            i=len2-1;
        }
        for(k=0;k<=i;k++)
            d[k]=b[k];
        if(d[k-1]=='.')
            d[k-1]='\0';
        else
            d[k]='\0';

        if(strcmp(c,d)==0)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}
//法二:去.0000
#include<stdio.h>
#include<string.h>
char a[100000],b[100000];
void change(char s[])
{
    
    
    int len,i;
    len=strlen(s);
    if(strstr(s,"."))  //如果它有小数点
    {
    
    
        for(i=len-1;s[i]=='0';i--)  //在刨小数点后边的0
        {
    
    
            s[i]='\0';   //最后加个\0结束符号
            len--;
        }
    }
    if(s[len-1]=='.')
        s[len-1]='\0';
}
int main()
{
    
    
    while(~scanf("%s%s",&a,&b))
    {
    
    
        change(a);
        change(b);
        if(strcmp(a,b)==0)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

六、等差数列的一个应用

问题描述 :给出一个序列 1–n, 求出可能的子序列,该子序列的和是m
如果写两层循环,会时间超限
在这里插入图片描述

#include <stdio.h>
#include <math.h>
long long  n, m, a, i, t;
int main(void){
    
    
    while(1){
    
    
        scanf("%lld %lld", &n, &m);
        if(n == 0 && m == 0){
    
    
            return 0;
        }
        else{
    
    
            t = sqrt(2 * m);//跟除法有关的,判断了前面的,比如100=10*10,这里是乘的关系,循环到那就可以了。
            for(i = t; i >= 1; i--){
    
    
                a = (m - i*(i+1) / 2) / i;  //等差数列 
                if( a*i + i*(i+1)/ 2 == m){
    
    
                    printf("[%lld,%lld]\n", a+1, a+i); //注意是a+1,仔细看原理。
                }
            }
        }
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_51508220/article/details/113106989