OJ1208

问题 A: 22-字符串-2-相邻相同字母删除

题目描述

小南现在有一段由小写字母组成的文本s,他每天的工作就是找到文本中两个相邻并且相同的字母,然后删除它们。注意这个删除过程可能是重复的,比如:
"abbac"->"aac"->"c"。 也就是说最终的文本中没有相邻相同的字母。

输入

单样例。每个测试文件只有一个样例输入,输入的一行文本的长度len满足1≤len≤105。

输出

输出一行,代表处理后的文本。

样例输入 Copy

abbbac

样例输出 Copy

abac

解法1

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>

#define MaxSize 100000

int main(void)
{
    int sum1=0, sum2, len;
    char a[MaxSize] = {'\0'};

    scanf("%s", a);
    len = strlen(a);

    do
    {
        sum2 = len;
        sum1 = 0;
        int i = 0;
        for (i = 1; i < len; i++)
        {
            if (a[i - 1] != a[i])
                a[sum1++] = a[i - 1];
            
            else
                i++;
        }
        
        if (len == i)
            a[sum1++] = a[i - 1];

        /*要不要都行,关键是上面这一步
        for (int k = sum1;k < len;k++)
            a[k] = '\0';
        */
        len = sum1;

    } while (sum1!=sum2);/*不断比较,确定最后得到的字符
                         串不能再删除*/

    for (int i = 0;i < sum1;i++)
        printf("%c", a[i]);

    return 0;
}

方法2

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
    char s[100001];

    scanf("%s", s);

    int len = strlen(s);

    int i,sign = 1;

    while (sign == 1)//这个思路有点像消除《C语言程序设计·现代方法》里面消除相同数字的思路
    {
        sign = 0;
        for (i = 0;i < len - 1;i++)
        {
            if (s[i] == s[i + 1])
            {
                for (int k = i+2; k < len; k++)
                    s[k - 2] = s[k];//本来想用字符串拼接,但是操作起来有点麻烦算了
                len = len - 2;
                s[len] ='\0';
                sign = 1;
            }
        }
    }
    printf("%s", s);
}

问题 B: 22-字符串-2-字符串相减

题目描述

小南现在有两个字符串S1和S2,他定义了一种字符串减法,S1-S2即在S1中去除掉所有S2中的字符所剩下的字符串。
举例: S1="ABA", S2="A",则 S1-S2="B"。

输入

输入包含多组测试用例。每组测试用例包括两个字符串S1和S2,字符串长度不超过104。每个字符串都是由可见ASCII字符和空格组成。

输出

对于每组测试用例,输出S1-S2的结果。每个输出占一行。

样例输入 Copy

ABA
A
A B&&1
&

样例输出 Copy

B
A B1

提示

对于输入包含空格的字符串时,最好采用while(gets(a)!=NULL)处理多样例。


总结:首先想到遍历循环,但是超限;又想到ASCII表每个字符都有其代表的特定值,不如用数组对其标记。

(VS2019不能识别gets,要用gets_s)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int main()
{
	char str1[10001];
	char str2[10001];
	int len1, len2;
	while ((gets_s(str1)) != NULL)
	{
		int a[128] = { 0 };//ASCII码127个

		gets_s(str2);
		len1 = strlen(str1);
		len2 = strlen(str2);//不要在程序中反复调用strlen函数
		for (int i = 0;i < len2;i++)
		{
			a[str2[i]] = 1;//对于str2中出现的ASCII码标记为1;
		}

		for (int i = 0;i < len1;i++)
		{
			if (!a[str1[i]]) //这比一遍遍访问删除方便多了w
			printf("%c", str1[i]);
		}
		printf("\n");
	}

	return 0;
}


问题 C: 22-数组-3-统计数字

题目描述

小南跟着导师进行科研调查,得到了n个自然数(1≤n≤200000),每个数均不超过1500000000(1.5*109),即long型。已知不相同的数不超过10000个,现在需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺序输出统计结果。你能帮他编程实现吗? 
 

输入

单样例。每个测试文件只包含一组测试数据:
第一行是整数n,表示自然数的个数;
第2~n+1行,每行一个自然数。
 

输出

输出包含m行(m为n个自然数中不相同数的个数),按照自然数从小到大的顺序输出。每行输出两个整数,分别是自然数和该数出现的次数,其间用一个空格隔开。
 

样例输入 Copy

8
2
4
2
4
5
100
2
100

样例输出 Copy

2 3
4 2
5 1
100 2

提示

也可以用结构体处理。


借鉴了网上大佬的做法,用了快速排序,如果用冒泡排序好像会超时。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

void quicksort(int x[], int left, int right);
int a[200005];//注意100%的数据<=200000,第一次就因为这个运行错误 

int main()
{
	int n, i, front, cnt;
	scanf("%d", &n);
	for (i = 0;i < n;i++)
		scanf("%d", &a[i]);

	quicksort(a, 0, n - 1);

	front = a[0];
	cnt = 1;
	for (i = 1;i < n;i++)  //i从1开始 
	{
		if (a[i] != front)
		{
			printf("%d %d\n", front, cnt);
			cnt = 0;  //注意cnt更新为0,而不是1 
		}
		front = a[i];//更新front 
		cnt++;   //更新计数器 
	}
	printf("%d %d\n", front, cnt);  //不要漏了最后一个数 
	return 0;
}


void quicksort(int x[], int left, int right)  //快速排序 
{
	if (left < right)
	{
		int i = left, j = right, key = x[left];//x[left]是分割元素,把它复制到key这个位置
		while (i < j)
		{
			while (i<j && x[j]>key)
				j--;
			if (i < j)
				x[i++] = x[j];

			while (i < j && x[i] < key)
				i++;
			if (i < j)
				x[j--] = x[i];
		}
		x[i] = key;
		quicksort(x, left, i - 1);
		quicksort(x, i + 1, right);
	}
}

问题 D: 22-循环-2-多项式相加

题目描述

小南继续研究A+B的问题。这个时候的A和B分别代表两个多项式。请帮助小南实现两个多项式相加的算法。
两个多项式相加:相应指数的系数相加。例如当A为3X4-6X2+5X-10,B为1X4+6X3+5,则A+B的结果为4X4+6X3-6X2+5X-5。
说明:此题可以用循环或结构体或链表完成。
 

输入

单样例。样例的第一行输入包含两个整数m,n,分别表示多项式A的项数和多项式B的项数。
接下来的m行,每行包含两个用空格分开的整数a和b,代表多项式A的m项的系数和指数。
再接下来的n行,每行包含两个用空格分开的整数a和b,代表多项式B的n项的系数和指数。

输出

输出两个多项式相加的结果。输出格式为:从较高指数到较低指数,依次输出相加后多项式的系数和指数,每项输出一行。注意系数为0的项也不输出。

样例输入 Copy

2 3
1 2
1 1
2 2
1 1
2 0

样例输出 Copy

3 2
2 1
2 0

提示

也可以用链表来实现:一条单链表可以表示一个一元多项式,每个节点包含三个域:指数、系数和后继节点的指针。


总结:这题思路比较清晰,用循环和数组就可以解决了

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

int main(void)
{
	int m, n, m1[10000] = {0};
	int a, b,max=0;

	scanf("%d%d", &m, &n);
	for (;m > 0;m--)
	{
		scanf("%d %d", &a, &b);
		m1[b] = a;
		if (b > max)
		max = b;
	}

	for (;n > 0;n--)
	{
		scanf("%d %d", &a, &b);
		m1[b] = a+m1[b];
		if (b > max)
		max = b;
	}

	for (;max >= 0;max--)
	{
		if(m1[max]!=0)
		{
			printf("%d %d\n", m1[max], max);
		}
	}

	return 0;
}

问题 E: 分割排序

题目描述

输入一行数字,如果我们把这行数字中的‘5’都看成空格,那么就得到一行用空格分割的若干非负整数(可能有些整数以‘0’开头,这些头部的‘0’应该被忽略掉,除非这个整数就是由若干个‘0’组成的,这时这个整数就是0)。
你的任务是:对这些分割得到的整数,依从小到大的顺序排序输出。

输入

每组输入数据只有一行数字(数字之间没有空格),这行数字的长度不大于1000。  
输入数据保证:分割得到的非负整数不会大于100000000,输入数据不可能全由‘5’组成。

输出

输出分割得到的整数排序的结果,相邻的两个整数之间用一个空格分开,每组输出占一行。

样例输入 Copy

0051231232050775

样例输出 Copy

0 77 12312320

qsort,关于5的小细节,数字字符转换成字母

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int cmp(const void* a, const void* b)
{
	return (*(int*)a - *(int*)b);//(int*)a是指针
}


int main()
{
	char s[1001];
	
	while (scanf("%s",s)!=EOF)
	{ 
		int a[1000];
		int len = strlen(s);
		int sum = 0,k=0;

		for (int i = 0; i < len;)
		{
			if (s[i] != '5'&&i<len)
			{
				sum = sum * 10 + s[i] - '0';
				
				if (i == len - 1)//不要忘记“...5100”这种末尾不是5的情况,否则最后那个数就保存不进a[k++]了
					a[k++] = sum;
				
				i++;
			}

			else if(i!=0)
			{
				
					a[k++] = sum;
					sum = 0;
					do
					{
						i++;
					} while (s[i] == '5');
			}

			else if (s[0] == '5')//滤掉开头的5,否则会多个0
			{
				do
				{
					i++;
				} while (s[i] == '5');
			}
		}

		qsort(a, k, sizeof(int), cmp);

		for (int i = 0; i < k; i++)
		{
			printf("%d ", a[i]);
		}

		printf("\n");

	}

	return 0;
}

在这里加几个函数,可以将字符串转化为数字:

#include <stdlib.h>

函数:

atoi:可以把字符串转为int

atol:可以把字符串转为long

atof:可以把字符串转为double

    /*
     * 程序名:book.c,此程序用于演示atoi函数族。
     * 作者:C语言技术网(www.freecplus.net) 日期:20190525。
    */
   

 int main()
    {
      int ii=0;
      ii=atoi("123");
      printf("ii=%d\n",ii);  // 输出ii=123
     
      ii=atoi("123abc");
      printf("ii=%d\n",ii);  // 输出ii=123,合法数字后的abc被忽略。
     
      ii=atoi("abc123");
      printf("ii=%d\n",ii);  // 输出ii=0,数字前有字符为非法。
     
      ii=atoi("+123");
      printf("ii=%d\n",ii);  // 输出ii=123,+是合法字符。
     
      ii=atoi("-123");
      printf("ii=%d\n",ii);  // 输出ii=-123,-是合法字符。
    }


————————————————
版权声明:本文为CSDN博主「栩云」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/2203_75466358/article/details/128402138


问题 F: 22-字符串-3-最小回文串

题目描述

回文数是从前往后和从后往前得到的数是相同的。小南接到老师布置的任务,就是对给定的正整数n,找到比n大的最小的那个回文数p。由于n(0 <n< 1010000)可能是一个很大的数,所以只能用字符串来处理。你能帮他编写一个程序实现吗?

输入

多组样例。每组样例输入一个正整数n(0 <n< 1010000),并且n不会有前导0。

输出

对于每组输入,输出比n大的最小的那个回文数p。每个结果占一行。

样例输入 Copy

44
3
175
9
99
1331
19991

样例输出 Copy

55
4
181
11
101
1441
20002

 这道题想+写了好久,但是没过orz,以下是强大的互联网的答案。我们总体思路是差不多的,但是ta的代码就比较简洁。如果读者有更好的答案,欢迎交流讨论=w=

窃以为值得思考的地方:9进位的特殊情况(包括全是9)、字符串长度是奇/偶数、简化输出

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>

int main(void)
{
    char a[10001];
    while (scanf("%s", a) != EOF)
    {
        int len, flag = 1;
        len = strlen(a);
        for (int i = len / 2 - 1;i >= 0;i--)
        {
            if (a[i] > a[len - i - 1])//即从中间镜面对照看,前半部分字符串
                                      //比后半部分大,这种情况只要改字符串后半部分就可以了
            {
                flag = 0;break;
            }
            else if (a[i] < a[len - i - 1])//(从中间镜面对称角度看)后半部分比前半大或
                                           //s[len]是回文字符串
            {
                flag = 1;
                break;
            }

        }
        if (flag)
        {
            for (int i = (len - 1) / 2;i >= 0;i--)
            {
                a[i]++;

                if (a[i] > '9')//也就是a[i]在"a[i]++;"操作前就是'9' 
                    a[i] = '0';//如果不跳出for,下一次a[i]++就相当于进一;

                else 
                    break;
            }

            if (a[0] == '0')//这种就是输入的回文字符串是9999...99(全部是9)的情况了
            {
                a[0] = '1';
                len++;
                a[len / 2] = '0';
            }
        }

        //前面算是得出了目标回文字符串的前半部分,后半部分倒着输出就好了,但是这也是个技术活qaq
        for (int i = 0;i <= (len - 1) / 2;i++) //a[(len-1)/2]恰好是一个奇数字符串最中间那个
                                               //字符,偶数字符串
            printf("%c", a[i]);
        for (int i = len / 2 - 1;i >= 0;i--)
            printf("%c", a[i]);//a[len/2-1]恰好是一个奇数字符串中间向右数第一个字符,偶数字符串
                               //中间向右数第一个字符
        printf("\n");
        //根据奇偶数特性、数组下标从0开始等等,可以推出这个微妙的位置关系,希望读者能分享关于此简洁的理解

    }
    return 0;
}

问题 G: 22-数组-2-上下火车

题目描述

火车从始发站(称为第1站)开出,在始发站上车的人数为w,然后到达第2站,在第2站有人上、下车,但上、下车的人数相同,都是t,因此在第2站开出时(即在到达第3站之前)车上的人数保持为w人。从第3站起(包括第3站)上、下车的人数有一定规律:上车的人数都是前两站上车人数之和,而下车人数等于上一站上车人数,一直到终点站的前一站(第n-1站),都满足此规律。现给出的条件是:共有n个车站(1≤n≤100),始发站上车的人数为w,最后一站下车的人数是m(全部下车)。需要求解x站开出时车上的人数是多少。小南通过统计发现了每一站开车时车上的人数与始发站人数w以及第2站上车人数t之间的规律,通过这个规律他很快得到了答案,你知道他是怎么实现的吗?

输入

单样例。每个测试文件只包含一组测试数据,输入的一行包括四个整数w、n、m和x(均不超过int数据类型,其中1≤n≤100)。

 

输出

对于输入的一组测试数据,输出一个整数,代表从x站开出时车上的人数。

 

样例输入 Copy

5 7 32 4

样例输出 Copy

13

本来想算出w总数,再求出t总数,再求t(求t是关键),发现山路十八弯...遂还是上网找答案,发现它直接遍历找出t了(可能料这样也不会有久(?))

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

int main(void)
{
    const int N = 2e4 + 1;

    int up[N], down[N], f[N];
    int a, n, m, x; 
    
    scanf("%d %d %d %d", &a, &n, &m, &x);
    
    up[1] = a; down[1] = 0;
    
    for (int b = 0; b <= N; b++) 
    {
        up[2] = down[2] = b;

        for (int i = 3; i <= n; i++) 
        {
            up[i] = up[i - 1] + up[i - 2];
            down[i] = up[i - 1];
        }

        f[1] = a;

        for (int i = 2; i <= n; i++) 
        {
            f[i] = f[i - 1] + up[i] - down[i];
        }

        if (f[n - 1] == m) 
        {
            printf("%d",f[x]);
            break;
        }
    }
    return 0;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值