问题 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;
}