文章目录

  • 1.字母转换为大写
  • 4.24
    • ① 2.小猴记单词 1125
    • ② 3.花生采摘
  • 4.25
    • ①删除链表节点
    • ②删除倒数第n个节点
  • 4.26
    • ①反转链表
  • 4.27
    • ①171.转化为26进制,excel表中的字母转数字
    • ②蛇形方阵5731
  • 4.28
    • ①外观数列
    • ②口算练习题
  • 4.29
    • ①标题统计
    • ②P5734 文字处理软件
    • ③p1308统计单词数
  • 4.30
    • ①p1765手机
    • ②p3741 VK键盘
  • 5.1
    • ①p1553 数字反转
  • 5.9
    • ①括号匹配判断
  • 5.10
    • ①回文链表
  • 5.24 模拟与高精度
    • 一。框架
    • 1.[NOIP2003 普及组] 乒乓球
    • 2.[NOIP2010 普及组] 接水问题
  • 5.25
    • 1.扫雷游戏P2670
主要记录字符串题,暂时 刷力扣有 逆反 心理,故从洛谷新手着手

1.字母转换为大写

1.小写字母a ~ z的ANSI码范围97~122
大写字母A ~ Z的ANSI码范围65~90
差值32
带引号的’a’(符号)就是97(ANSI码值)
2.也可以使用toupper函数

#include<stdio.h>
#include<string.h>
#include<stdlib.h>int main()
{char a[100];int i;gets(a);int n=strlen(a);for(i=0;i<n;i++){a[i]=toupper(a[i]);//1.
//      if(a[i]>='a'&&a[i]<='z')//同义于a[i]>=97 <=122
//          a[i]=a[i]-32;  //2.}printf("%s",a);return 0;
}

4.24

① 2.小猴记单词 1125

4.24算法1
统计每个字符出现的次数

题目 1125笨小猴

初步想法
//1.统计每个单词出现的次数(这里*有问题* ,想法太过繁琐,创建两个数组做标记,不推荐),找到最大最小值
//2.最值作差,判断质数输出 Lucky Word,并且输出差值:否则输出 No Answer

解决问题:字母转化为数字 a[i]-‘a’ ,作为数组下标,起数组sum[a[i]-‘a’]++作标记,第一个元素表示a
方便:不用定义记录字母有没有在单词中出现过的数组,sum[i]>0

#include<stdio.h>
#include<string.h>//memset头文件,统一初始化
#include<stdlib.h>
#include<stdbool.h>//bool类型头文件
#include<math.h>bool f(int n) {int i;if( n == 1 || n == 0)  return false;for(i = 2; i <= sqrt(n); i++)  {if(n % i == 0) {return false; //有一个即判断非质数 }}return true;
}int main() {char s[105];scanf("%s",s);int maxn = 0, minn = 1000, n = strlen(s), i, x, a[1000];memset(a, 0, sizeof(a));//统计每个字母出现的次数,并排除已经出现过的字母//排除想用数组p做标记,p[i]=1; for(i = 0; i < n; i++) {//a统计数组,p标记是否读取过
//      for(j = i + 1; j < n - 1; j++) {   //!最后一个字母!
//          if(s[i] == s[j]) {//              p[j] = 1;//标记后边的字母已经读取过
//              a[i]++;
//          }
//      }
//      if(maxn < a[i]) {//          maxn = a[i];
//      }
//      if(minn > a[i]) {//          minn = a[i];
//      }a[s[i]-'a']++;//帅!挨个遍历统计数组元素 if(a[s[i]-'a'] > 0 && a[s[i]-'a'] < minn) {minn = a[s[i]-'a'];}  else if(a[s[i]-'a'] > maxn) {maxn = a[s[i]-'a'];}}x = maxn - minn;if(f(x)) {                       //判断质数 printf("Lucky Word\n");printf("%d",x);}   else {printf("No Answer\n0");}return 0;}

② 3.花生采摘

4.24.算法2.

①用到曼哈顿距离算法

想法:
创建一个递归函数,不断存位置加距离,根据与最大路线判断,退出递归,
//按顺序采摘,采摘前要判断剩下的步数够不够走向下一个最大数

#include<stdio.h>
#include<math.h>void dfs(int x0,int y0,int time0);//x是行,y是列 int m,n,k,sum = 0;
int a[25][25];int main()
{int i,j;scanf("%d%d%d",&m,&n,&k);for(i = 1; i <= m; i++){for(j = 1; j <= n; j++){scanf("%d",&a[i][j]);}}dfs(0,0,k);printf("%d",sum);return 0;
}void dfs(int x0,int y0,int time0) //从路边开始走,总时间
{int x,y,time; //动态走 int maxx = 0;int i,j;for(i = 1; i <= m; i++) {for(j = 1; j <= n; j++) {if(a[i][j] > maxx) {maxx = a[i][j];//找到最大值(有花生) x = i;y = j;//存位置 }}}if(y0 == 0) {//判断是否是第一步,即从路面走到花生田y0 = y;}time = fabs(x - x0) + abs(y - y0) + x + 1;// 已经走的步数 +1是暂停 if(time0 < time || a[x][y] == 0) { //走的路大于总步数或者走到边边 return;} else {    // 判断后边的步数是否足够走到下一个最值处 sum += a[x][y];//走向下一个地方 a[x][y] = 0;dfs(x,y,time0 - abs(x - x0) - abs(y - y0) - 1);//递归,不断循环 }
}

4.25

①删除链表节点


想法
法一:
双链表,
创建一个前驱结点和一个后继结点
通过本结点的前驱结点的后继结点指向本结点的后继点删除本节点

typedef struct node {int data;struct node* pre;struct node* next;
}Node, *Link;Link Init() {Node *head;head = (Node *)malloc(sizeof(Node));head->pre = NULL;head->next = NULL;return head;
}void Creat(Link head) {Node *p = head, *q;int data;printf("输入链表数据:\n");while(1) {scanf("%d",&data);if(data == 0) {break; }q = (Node *)malloc(sizeof(Node));q->pre = NULL;q->next = NULL;q->data = data;p->next = q;q->pre = p;p = p->next; }
//  p->next = NULL;
}
void Delete(Link head,int n) {Node *p = head, *q;while(p) {if(p->data == n) {break;}p = p->next;}if(p && p->next != NULL) {p->pre->next = p->next;free(p); }
}

法二:
单链表:
只创建后继结点
加一个中间变量q做过度,q=p,
p->next = q->next;

void Creat(Link head) {Node *p = head, *q;int data;printf("输入链表数据:\n");while(1) {scanf("%d",&data);if(data == 0) {break;   }q = (Node *)malloc(sizeof(Node));q->data = data;p->next = q;p = q;}p->next = NULL;
}void Delete(Link head,int n) {Node *p = head, *q;while(p) {if(p->data == n) {break;}q = p;p = p->next;}if(p && p->next != NULL) {q->next = p->next;//free(p); }
}

简便点:

void Delete(Link head, int a) {Node *p = head, *q;if(p->data != a) {p = p->next;}q = p->next;p->next = q->next;free(q);
}

无头节点
p->data = p->next->data;
p->next = p->next->next;

②删除倒数第n个节点


思路
想法一:
计算链表总长度,通过传长度以及特定位置,删除节点(1)

int length(Link head) {int n = 0;Node *p = head->next;while(p) {n++;p = p->next;}return n;
}void Delete(Link head, int a) {Node *p = head, *q;int pos;while(pos < length(head)-a && p) {pos++;p = p->next;}if(p) {q = p->next;p->next = q->next;}
}

简便点:

void Delete1(Link head, int n) {Node *p = head, *q;int pos = 0;    if(pos != n) {pos++;p = p->next;}q = p->next;p->next = q->next;free(q);
}

想法2:
快慢指针:

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){struct ListNode* fast, *slow;int i;fast = head;slow = head;for(i = 0;i < n;i++) {fast = fast->next;}if(fast == NULL) {return head->next;}while(fast->next != NULL) {fast = fast->next;slow = slow->next;}slow->next = slow->next->next;return head ;
}

4.26

①反转链表


很不习惯力扣只能提交无头结点的链表,用有头结点的链表做输出会将首节点看做无效的头结点,作用于从第二个数开始之后。
思路一
再构造一个链表,将该链表中的每一个数都作为新链表的头节点
原 1 2 3 4 NULL ; 新 NULL
1.
原 1 2 3 4 NULL ; 新 1 NULL
2.
原 1 2 3 4 NULL ; 新 2 1 NULL
3.
原 1 2 3 4 NULL ; 新 3 2 1 NULL
4.
原 1 2 3 4 NULL ; 新 4 3 2 1 NULL

Link Reverse(Link head) {Node *p = NULL, *q; //pÊÇÐÂÁ´±íµÄÊ×½áµã while(head) {          q = head->next;  //q×÷Ϊ²»¶ÏÑ­»·Ã½½é head->next = p;p = head;head = q;}return p;
}

4.27

①171.转化为26进制,excel表中的字母转数字

思路
我一直很颠倒ANSI码的使用,这里使用单引号作差可以得到数字差值,加一即表示 excel中字母的大小 ,再乘以26的位置次方可得到数字值

int main()
{long long n=0,t=1,i=0;char s[26] = {0};printf("你将转化的字母是:\n");scanf("%s",s);int m=strlen(s);for(i=m-1;i>=0;i--){n += t*(s[i]-'A'+1);      //我一直很颠倒ANSI码的使用,这里使用单引号作差可以得到数字差值,加一即表示 excel中字母的大小 t*=26;                      //①t=pow(26,0) ②t=pow(26,1)... }printf("转化成数字是:%d\n",n);return 0;
}

②蛇形方阵5731


初步想法写出四个外部基本规律,问题在于如何运用到循环中,i,j,x,y 关系
优化解法

1.既然有四个规律,那就给蛇,如果越界或位置被占,不断转头,不断向右转
2.不断打印上下左右,t=1,t++;以 t<nn 作为最终判断结束打印。打印条件是旁边位置为空且不出界*

1.*越界或位置被占*,不断转头,不断向右
#include<stdio.h>
int a[15][15],i,j;//记录输出的数组
int pos[4][2]={0,1,1,0,0,-1,-1,0};//改变位置的数组//0表示右,1表示下,2表示左,3表示上
int main(){//主函数int n=0,x=1,y=1,d=0;//初始化scanf("%d",&n); for(i=1;i<=n*n;i++){//遍历a[x][y]=i;//赋值int tx=x+pos[d][0],ty=y+pos[d][1];//核心代码,解释见上if(tx<1||tx>n||ty<1||ty>n||a[tx][ty]) d=(d+1)%4;//出界或旁边位置被占,转弯 x+=pos[d][0],y+=pos[d][1];}for(i=1;i<=n;i++){//输出for(j=1;j<=n;j++) printf("%3d",a[i][j]);//注意%3dif(i<n) printf("\n");}return 0;//华丽结束
}

4.28

①外观数列


思路:
递归 加 双指针
边说边数 字符串指针(拿捏分配空间大小)
遍历字符串,对连续相邻字符串计数,记得数存储在数组中,注意转化ANSI,被记得数放在记得数之后,重置为1,不断开辟空间,循环。
:‘0’与ANSI码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//递归加双指针
//边说边数  字符串指针,不要字符串数组
char* f(int n) {if(n == 1) {return "1"; }char *s = f(n-1); //s是最终序列,r不断添加  char *r = (char*)malloc(5000); int cnt = 1, i = 0;while(*s != 0) {  //0作为判断条件 if(*s == *(s+1)) {cnt++;  //连续的数字计数 } else {r[i++] = cnt + '0';//数量cnt存储 r[i++] = *s;      //被计数的数字在cnt后cnt = 1;           //重置cnt为1}s++;        //向后遍历其他数字 }r[i] = 0;return r;
}
int main() {int n;scanf("%d",&n);char *a = f(n);printf("%s",a);return 0;
}

②口算练习题

自己的算法实在差,开始就练习力扣实在打击,造成逆反更加不想刷,就还是从洛谷的新手刷吧。

初步想法:
while循环,输出用printf返回值减一
问题:我得循环输入必须是3个(%c输入需要&,%s不需要),与题目2个输入与上一运算类型相等不符,
优化
通过判断循环内第一个是字母(存储)还是数字(使用sscanf ( 掌握[], ^, *如何使用))是数字存储到倒数第二个数字中,输入最后一个数字.注意mamset清空字符串,防止长度判断错误,sprintf格式化的数据写入字符串
例如:

char b[10] = {0,1,2,3,4,a,b,c};
sscanf(b,“%10[0-9]”,&c);
把数组b中含有的0-9的数字写入c;
前至后读写

char a[] = {‘1’, ‘2’, ‘3’, ‘4’};
char b[] = {‘5’, ‘6’, ‘7’, ‘8’};
char buffer[10];
sprintf(buffer, “%.4s%.4s”, a, b);后至前读写
连接a,b数组读写入buffer数组

#include<stdio.h>
#include<string.h>
int main() {char a;int n, c, d, i;char s[100], b[10];//s存储最终字符串,b临时变量scanf("%d",&n);for(i = 0;i < n;i++) {scanf("%s",b);  //判断循环输入的是字符串还是数字 if(b[0] >= 'a' && b[0] <= 'z') {a = b[0];  //是运算符存入a scanf("%d%d",&c,&d);} else {sscanf(b,"%d",&c);//是数字就转换b为int存储到第一个数字 scanf("%d",&d);//输入二个数字 }memset(s,0,sizeof(s));//清空sif(a == 'a') {sprintf(s,"%d+%d=%d",c,d,c+d);} else if(a == 'b') {sprintf(s,"%d-%d=%d",c,d,c-d);} else if(a == 'c') {sprintf(s,"%d*%d=%d",c,d,c*d);}     printf("%s\n%d\n",s,strlen(s));   }   return 0;
}

4.29

①标题统计

在这里水一道题,一个小点
字符串输入scanf与gets
gets(s)函数与 scanf(“%s”,&s) 相似,但不完全相同,使用scanf(“%s”,&s) 函数输入字符串时存在一个问题,就是如果输入了空格会认为字符串结束,空格后的字符将作为下一个输入项处理,但gets()函数将接收输入的整个字符串直到遇到换行为止。

思路:
标题中可能包含大、小写英文字母、数字字符、空格和换行符。统计标题字 符数时,空格和换行符不计算在内。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main() {char a[100];int n, i = 0, cnt = 0;
//  scanf("%s",a);gets(a);n = strlen(a);while(n--) {if(a[i] >= 'a' && a[i] <= 'z' || a[i] >= 'A' && a[i] <= 'Z' || a[i] >= '0' && a[i] <= '9') {cnt++;}i++;}printf("%d",cnt);return 0;
}

②P5734 文字处理软件


思路
循环n次内输入字符串b , 根据b[0]赋值给 a 判断类型,分装函数。
1.后插使用sprintf或者strcat(字符串拼接)都可

char f1(int b[]) { //后插 char str[100], p[100];gets(str);sprintf(p,"%s%s",b,str);    // return p;
}

2.strcpy了!截止位置后置零,开始位置首地址重新存储临时变量中,再将临时变量中的覆盖到原函数

char f2(int b[]) {  //截取 c到d字符串 int c, d;char p[100]; scanf("%d%d",&c,&d);b[c+d] = '\0';//strcpy(p,&b[c]); strcpy(b,p);return b;
}

3.strcat(覆盖原dest结尾处的’\0’),并添加新的’\0’。),题目要求放在之前,确定位置后面的数 连接 将要插的数组后 ,重置将要插后面(已存),连接

char f3(int b[]) { // 特定位a之前插入pint a;char p[100]; scanf("%d%s",&a,p);strcat(p,&b[a]); //后面的数连接将要插的数组后 b[a] = '\0';   //重置将要插后面(已存) strcat(b,p);  //连接 return b;
}

√找到一个和str[0]str[0]相等的字符,就往后判断是否相等

void f4(int b[]) { //查找 返回首地址位置 char p[100], l = -1;scanf("%s",p);bool flag;int i;for(i = 0;i < strlen(b) - strlen(p)+1;i++) {int j = 0;flag = false;while(b[i++] == p[j++] && j < strlen(p)) { //判断子字符串是否相等 flag = true;}if(j == strlen(p)) {l = i - j;   //i往后j个,需要减去 break;}if(flag) {i--;//找到了和p[0]相等的字符但不是答案之后加上一个i--} }printf("%d",l);
}

×查找子字符串1.strstr返回出现的首地址,否则返回null
2.strchr同样返回查找字符首地址

 char a[10] = {"abcdef"};printf("%s\n",strchr(a,'c')); //ANSI码值 printf("%s\n",strstr(a,"c")); //元素

均打印出 cdef
omg 强制类型转化 int(q-b) nonono c语言不允许!)

问题:
2.截取字符串中 指定位 (不是后面所有都输出)
只保留文档中从第 a 个字符起 b 个字符,
很可惜c语言不提供substr函数:substr(a,b,2,6);将b串中第2个字符起,后6个放入a数组中。

③p1308统计单词数

和考核题目以及上题第四步很像


思路:
转化大写为小写,(32)
创建两个指针,遍历文章一一对比单词是否相等
利用strstr(返回首次出现的指针否则返回NULL(空指针))

问题:可能出现两次该字符串,如何标记第一次字母出现的位置,而不会被第二次覆盖
flag仅标记第一次,为true后再
收获
tolower返回值为 int 类型,你可能需要隐式或者显式地将它转换为 char 类型
对于 tolower(),仅当有且只有一个对应的小写字母时,这种转换才能成功;如果没有对应的小写字母,或者有多个对应的小写字母,那么转换失败。转换成功返回对应的小写字母,转换失败直接返回 c(值未变)。

char ch = 'A';ch = tolower(ch);printf("ch=%c\n",ch);ch = 'b';ch = toupper(ch);

isupper
函数isupper()采用整数形式的单个参数,并返回int类型的值 。
既然都只针对单个字符,那循环就能改变字符串
对了,c语言仅支持 to 开头,不支持 is 开头

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stdbool.h>
int main() {char a[15], b[1000005], *p, *q;//p是当前搜索的地方,q最后一次找到单词的指针 bool flag = false;gets(a);//单词 gets(b);//文章 int n = strlen(a), m = strlen(b), i, cnt = 0, ans = -1;//cnt计数,ans初值是-1,没找到直接输出 for(i = 0;i < n;i++) {a[i] = tolower(a[i]);}for(i = 0;i < m;i++) {b[i] = tolower(b[i]);}p = b;//指针指向文章 for(;q = strstr(p,a);) { //循环,q取strstr搜索函数的返回值 if(q != NULL &&   //找到 (q == b || *(q-1) == ' ') && //防止越界与判断空格 (*(q + n) == '\0' || *(q + n) == ' ')) { //后面也是空格 cnt++;if(flag == false) { //首次找到 flag = true;ans = q - b; //第一个位置 }}p = q + n; //刷新指针 } if(flag == true) {printf("%d %d",cnt,ans);} else {printf("%d",ans);}return 0;
}

4.30

①p1765手机



caicai思路:
caicai第一思路就是打表,吧每一个数首字母,第2,3,4个字母分别用if敲出来,再进行sum+=1,2,3,4;
实现一下:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main() {char a[100];gets(a);int n = strlen(a), i, cnt = 0;for(i = 0;i < n;i++) {if(a[i] == 'a' || a[i] == 'd' || a[i] == 'g' || a[i] == 'j' || a[i] == 'm' ||a[i] == 'p' || a[i] == 't' || a[i] == 'w' || a[i] == ' ') {cnt += 1;} else if(a[i] == 'b' || a[i] == 'e' || a[i] == 'h' || a[i] == 'k' || a[i] == 'n' ||a[i] == 'q' || a[i] == 'u' || a[i] == 'x') {cnt += 2;} else if(a[i] == 'c' || a[i] == 'f' || a[i] == 'i' || a[i] == 'l' || a[i] == 'o' ||a[i] == 'r' || a[i] == 'v' || a[i] == 'y') {cnt += 3;} else if(a[i] == 's' || a[i] == 'z') {cnt += 4;}}printf("%d",cnt);return 0;
}

大佬想法:
也是打表,不过是打每个数字,更简洁

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main() {int cnt = 0, i;int num[26] = {1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,1,2,3,1,2,3,4};char b[100];gets(b);int n = strlen(b);for(i = 0;i < n;i++) {if(b[i] >= 'a' && b[i] <= 'z') {cnt += num[b[i] - 'a'];}if(b[i] == ' ') {cnt += 1;}}printf("%d",cnt);return 0;
}

②p3741 VK键盘



caicai想法:
就是统计相邻特定字符串出现次数
这道题就是找两种子串

“VK”
“VV”或“KK”

果然想简单了~ ^ ~(才跑了6分5555)
问题:
1.题目要求输入整形与字符串,我就习惯性,scanf, gets a a巴嘎就在这里:如果在scanf后用gets需要注意一点,gets是遇到’\n’直接返回,而输入scanf后回车会将’\n’留在输入缓存里,而gets正好遇到’\n’就直接返回了,所以你没有机会输入。
解决就两个gets(a)咯
2.VK相邻时可以,但是最后一个例子过不去啊!要把计数过的筛掉,否则就是3咯

char a[102];
int main()
{gets(a);gets(a);int ans=0;for(int i=0;i<strlen(a);i++){if(a[i]=='V' && a[i+1]=='K'){ans++;a[i]='X';a[i+1]='X';}             //筛掉辣}for(int i=0;i<strlen(a);i++){if(a[i]!='X' && a[i]==a[i+1]){ans++;break;    //先从头到尾跑一遍,把正确的VK都改为X}}printf("%d",ans);return 0;
}

5.1

①p1553 数字反转




问题:
// 1.怎么判断是 小数,分数,百分数,整数。呢
//寻找符号 ,也就是非数字
// 2.这些可以都用gets或者%s输入吗?
// gets输入
// 3. 4个能用char类型表示吗?精度够吗
//可以的,分开数为两部分,注意存储符号

caicai看到题头已大
大佬思路:
分开数为两部分,注意存储符号

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{char s[100];char p = 0;//放符号 int cnt = 0, i; gets(s);int n = strlen(s);for(i = 0;i < n;i++) {if(s[i] >= '0' && s[i] <= '9') {cnt++;      //记录第一个数长度} else {       //遇到符号,记录,跳出         p = s[i];break;} }int x = cnt;//记下第一个数末后一个的位置,也就是符号的位置,如果是分数或小数就要用 cnt--;while(s[cnt] == '0' && cnt > 0) {cnt--; }//去除多余前导0; for(i = cnt;i >= 0;i--) {//输出第一部分数 printf("%c",s[i]);}if(p == 0) { return 0;//无符号return 0 } else if (p == '%') {printf("%c",p);return 0;} else { printf("%c",p);//其他继续 }int m = n-1;while(s[x+1] == '0' && x < m-1) {x++;//去除末尾0 }while(s[m] == '0' && m > x+1) {m--; //去除多余前导0}for(i = m;i > x;i--) {//输出第二部分数 printf("%c",s[i]);}return 0;
}

5.9

①括号匹配判断


初步想法:
手打栈,存储左边符号,遇到右边符号时化为左边存储,和存储到栈内的符号自顶向低一一比对,但是比对时对于 --top 出现了问题
想法优化:
遇到左i符号直接转换为右符号存储到 a[top++] 会方便很多,后续直接比较,
比较时采用 s[i] 与 a[–top] 的关系
注意

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stdbool.h>bool f1(char s[], int n) {int i = 0, top = 0, a[105];if(n % 2 == 1) {return false;}for(i = 0; i < n;i++) {if(s[i] == '{' ) {a[top++] = '}';   } else if(s[i] == '(') {a[top++] = ')';} else if(s[i] == '[') {a[top++] = ']'; }else {if(top < 1 || s[i] != a[--top]) {return false;}   }}if(top != 0) {return false;} else {return true;}
}
int main() {char a[105];gets(a);int n = strlen(a);if(f1(a, n)) {printf("true!\n");} else {printf("false!\n");}return 0;}

例:
( [ { } ( ) ] )

5.10

①回文链表


知识点:栈,快慢指针,递归,链表
初步想法:
利用栈,新链表放置前1半截数据,逆置链表后(后半截编程前半截2),前半截2数据和1数据比较
问题
选取前半截链表的方法太过繁琐(计算链表长度,还要判断奇偶)
解决:
方法1

快慢指针找中点后,通过fast != NULL得到链表结点数为奇数个 ,
然后反转后面一半的链表,和前面链表一一比对


Link Reverse(Link head) {Node *p = head, *q, *r;q = r = NULL;while(p) { q = p->next;p->next = r;r = p;p = q;} return r;
} bool Panduan(Link head) {Node *fast = head, *slow = head;while(fast != NULL && fast->next != NULL) {fast = fast->next->next;slow = slow->next;} //快慢指针找到中间,slow的指向 if(fast != NULL) {slow = slow->next; }//此时slow指向后半部分 slow = Reverse(slow); //反转后半部分 fast = head;//fast指向头 while(slow != NULL) {if(slow->data != fast->data) {return false;}fast = fast->next;slow = slow->next;} //对比反转后的链表和前面的数据。 return true;
}int main() {Node *wei = NULL, *tou = NULL; //没有头结点需要对第一个节点进行操作wei = Creatwei(wei);Output(wei);tou = Reverse(wei); Output(tou);if(Panduan(wei)) {printf("True!\n");} else {printf("false!\n");}return 0;
}

方法2;
栈 逆序存储前半部分再与后半部分一一比对
表的长度,将链表前面一般的元素入栈,然后逐个出栈与后一半的元素进行比较,如果一旦不相等立马返回FALSE,停止比较,如果到最后栈不为空也要返回FALSE,只有当栈为空且出栈的元素和链表后一半的元素都想得才能返回TRUE;另外要注意的一点是长度为1的链表都是回文链表所以要进行特殊处理,即当length=1时直接返回TRUE不用进行后续的操作。

int l(Link head) //计算长度
{Link p=head; int i=0; while(p!=NULL) {i++;p=p->next;}return i;
}
void push(Link *s,int n) //尾插法给新链表传送数据
{Link p;p=(Node *)malloc(sizeof(Node)); p->data=n; p->next=(*s); (*s)=p;
}
int pop(Link* s)
{int e=(*s)->data; (*s)=(*s)->next; return e;
}
int empty(Link S)
{if(S==NULL)return 0;elsereturn 1;
}
bool Panduan2(Link head){if(head==NULL) return false; //头为空,没有数,不是回文链表 Link S;  S=NULL; Link p=head; int length=l(head); //计算长度 if(length==1) return true; //链表中仅有一个数,是回文链表 int i;  for(i=1;i<=length/2;i++) //一半链表入栈 { push(&S,p->data); //将链表数据传入新链表 Sp=p->next; }  if(length%2!=0) //链表长度奇数 p=p->next; while(p!=NULL) { if(p->data==pop(&S)) //对比 p=p->next;else return false;}if(empty(S)==0&&p==NULL)return true;elsereturn false;
}

方法三:
递归
定义一个全局变量,保存头节点, 递归到最后和头结点比较

Link temp;bool check(Link head) {if(head == NULL) {return true; } bool res = check(head->next) && (temp->data == head->data);temp = temp->next;return res;
}bool Panduan3(Link head) {temp = head;return check(head);
}

5.24 模拟与高精度

一。框架

1.[NOIP2003 普及组] 乒乓球

题目背景

国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及。其中 111111 分制改革引起了很大的争议,有一部分球员因为无法适应新规则只能选择退役。华华就是其中一位,他退役之后走上了乒乓球研究工作,意图弄明白 111111 分制和 212121 分制对选手的不同影响。在开展他的研究之前,他首先需要对他多年比赛的统计数据进行一些分析,所以需要你的帮忙。

题目描述

华华通过以下方式进行分析,首先将比赛每个球的胜负列成一张表,然后分别计算在 111111 分制和 212121 分制下,双方的比赛结果(截至记录末尾)。

比如现在有这么一份记录,(其中 W\texttt WW 表示华华获得一分,L\texttt LL 表示华华对手获得一分):

WWWWWWWWWWWWWWWWWWWWWWLW\texttt{WWWWWWWWWWWWWWWWWWWWWWLW}WWWWWWWWWWWWWWWWWWWWWWLW

在 111111 分制下,此时比赛的结果是华华第一局 111111 比 000 获胜,第二局 111111 比 000 获胜,正在进行第三局,当前比分 111 比 111。而在 212121 分制下,此时比赛结果是华华第一局 212121 比 000 获胜,正在进行第二局,比分 222 比 111。如果一局比赛刚开始,则此时比分为 000 比 000。直到分差大于或者等于 222,才一局结束。

你的程序就是要对于一系列比赛信息的输入(WL\texttt{WL}WL 形式),输出正确的结果。

输入格式

每个输入文件包含若干行字符串,字符串有大写的 W\texttt WW 、 L\texttt LL 和 E\texttt EE 组成。其中 E\texttt EE 表示比赛信息结束,程序应该忽略 E\texttt EE 之后的所有内容。

输出格式

输出由两部分组成,每部分有若干行,每一行对应一局比赛的比分(按比赛信息输入顺序)。其中第一部分是 111111 分制下的结果,第二部分是 212121 分制下的结果,两部分之间由一个空行分隔。

样例 #1

样例输入 #1

WWWWWWWWWWWWWWWWWWWW
WWLWE

样例输出 #1

11:0
11:0
1:121:0
2:1

提示

每行至多 252525 个字母,最多有 250025002500 行。

(注:事实上有一个测试点有 250125012501 行数据。)
思路
遍历字符串,分别以11和21作为一组,重置计数器分别计数W,L,以E作为结束标志。
卡在了,如何分堆及输出 ,在那个位置重置计数器还要保证扫描的还是下一个数。
omg忽略了·一条信息:直到分差abs大于或者等于 22,才一局结束。
注意使用字符需要带 ‘ ’
大佬想法:
输入一个计数一个,使用另一个数组a存储,先使用11进制,再用a数组判断21进制

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
int main() {char s[10000];char a[10000];//s是输入字符串,a存储输入,用于21计数 int w = 0, l = 0, i = 0, j = 0;//w华华计分while(scanf("%c",&s[i]) && s[i] != 'E') {if(s[i] == 'W') {w++;a[i] = s[i];} if(s[i] == 'L') {l++;a[i] = s[i];}if( (w >= 11 || l >= 11) && ( abs(w-l) >= 2) ) {//11分且差值大于2,输出比值,并且置零 printf("%d:%d\n",w,l);w = 0;l = 0;}i++;//不断输入,循环 }printf("%d:%d\n",w,l);w = 0;l = 0;//有多的再输出,然后用字符串a进入21制 for(j = 0;j < i;j++) {if(a[j] == 'W') {w++;} if(a[j] == 'L') {l++;} if( (w >= 21 || l >= 21) && (abs(w - l) >= 2) ) {printf("%d:%d\n",w,l);w = 0;l = 0; }}printf("%d:%d\n",w,l);return 0;}

2.[NOIP2010 普及组] 接水问题

题目描述

学校里有一个水房,水房里一共装有mmm个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为$ 1$。

现在有$ n $名同学准备接水,他们的初始接水顺序已经确定。将这些同学按接水顺序从 111到$ n 编号,编号,编号,i $号同学的接水量为 wiw_iwi​。接水开始时,$1 到到到 m$ 号同学各占一个水龙头,并同时打开水龙头接水。当其中某名同学$ j 完成其接水量要求完成其接水量要求完成其接水量要求 w_j$后,下一名排队等候接水的同学 kkk马上接替 jjj 同学的位置开始接水。这个换人的过程是瞬间完成的,且没有任何水的浪费。即jjj 同学第 xxx 秒结束时完成接水,则$ k$ 同学第 x+1x+1x+1 秒立刻开始接水。若当前接水人数 nnn’不足 mmm,则只有 nnn’个龙头供水,其它 m−nm-nm−n’个龙头关闭。

现在给出 nnn 名同学的接水量,按照上述接水规则,问所有同学都接完水需要多少秒。

输入格式

第 111 行$ 2$ 个整数 nnn 和 mmm,用一个空格隔开,分别表示接水人数和龙头个数。

第 222 行 nnn 个整数$ w_1,w_2,…,w_n,每两个整数之间用一个空格隔开,,每两个整数之间用一个空格隔开,,每两个整数之间用一个空格隔开,w_i表示表示表示 i $号同学的接水量。

输出格式

111 个整数,表示接水所需的总时间。

样例 #1

样例输入 #1

5 3
4 4 1 2 1

样例输出 #1

4

样例 #2

样例输入 #2

8 4
23 71 87 32 70 93 80 76

样例输出 #2

163

提示

【输入输出样例 1 说明】

第 111 秒,$3 $人接水。第 $1 $秒结束时,$1,2,3 $号同学每人的已接水量为 $1,3 $号同学接完水,$4 $号同学接替 333 号同学开始接水。

第 222 秒,$3 人接水。第人接水。第人接水。第 2$ 秒结束时,$1,2 $号同学每人的已接水量为 $2,4 号同学的已接水量为号同学的已接水量为号同学的已接水量为 1$。

第 333 秒,$3 人接水。第人接水。第人接水。第 3$ 秒结束时,1,21,21,2 号同学每人的已接水量为 3,43,43,4 号同学的已接水量为$ $2。444 号同学接完水,555 号同学接替$ 4 $号同学开始接水。

第$ 4$ 秒,$3 $人接水。第 $4 $秒结束时,1,21,21,2 号同学每人的已接水量为 $4,5 号同学的已接水量为号同学的已接水量为号同学的已接水量为 1$。1,2,51,2,51,2,5 号同学接完水,即所有人完成接水的总接水时间为 444 秒。

【数据范围】

1≤n≤10000,1≤m≤1001≤n≤10000,1≤m≤1001≤n≤10000,1≤m≤100 且$ m≤n$;

1≤wi≤1001≤w_i≤1001≤wi​≤100。
思路:
数组(开大防止下溢)统计水,下标使用水龙头的序号,
接水的人从m+1 开始,以m + n 结束

#include<stdio.h>
int n,m,a[10005],turn,t,now[10005],i;
int main () {scanf("%d%d",&n,&m);   for(i = 1;i <= n;i++) { scanf("%d",&a[i]);} turn = m + 1;//接水的人向后移 while(turn < n + m ){ for(i = 1;i <= m;i++) { if(now[i] == 0) {  //now是还需接多少水 now[i] = a[++turn]; //a数组开得大,t = n + m不会越界 } now[i]--; //水量自减 } t++;//秒数自加 }printf("%d\n",t-1);return 0;
}

5.25

1.扫雷游戏P2670

题目描述

扫雷游戏是一款十分经典的单机小游戏。在nnn行mmm列的雷区中有一些格子含有地雷(称之为地雷格),其他格子不含地雷(称之为非地雷格)。玩家翻开一个非地雷格时,该格将会出现一个数字——提示周围格子中有多少个是地雷格。游戏的目标是在不翻出任何地雷格的条件下,找出所有的非地雷格。

现在给出nnn行mmm列的雷区中的地雷分布,要求计算出每个非地雷格周围的地雷格数。

注:一个格子的周围格子包括其上、下、左、右、左上、右上、左下、右下八个方向上与之直接相邻的格子。

输入格式

第一行是用一个空格隔开的两个整数nnn和mmm,分别表示雷区的行数和列数。

接下来nnn行,每行mmm个字符,描述了雷区中的地雷分布情况。字符’*’表示相应格子是地雷格,字符’?’表示相应格子是非地雷格。相邻字符之间无分隔符。

输出格式

输出文件包含nnn行,每行mmm个字符,描述整个雷区。用’*’表示地雷格,用周围的地雷个数表示非地雷格。相邻字符之间无分隔符。

样例 #1

样例输入 #1

3 3
*??
???
?*?

样例输出 #1

*10
221
1*1

样例 #2

样例输入 #2

2 3
?*?
*??

样例输出 #2

2*1
*21

提示

对于 100%100\%100%的数据, 1≤n≤100,1≤m≤1001≤n≤100, 1≤m≤1001≤n≤100,1≤m≤100。
思路: 遍历s[n][m]中每一个字符周围的8个,是*给cnt++,放在另一个数组a[110][110]中;
问题:很浪费空间,计数时对于8个 if 有什么优化方法。

解决1:
挨个输入一个字符标记 * 点为1 计入s数组,输出时将周围 8 个点求和,复杂度没变,但是会相比没个点8 个if还是简化的。
坑:这里输入字符需要在每一行前加入getchar回收回车,不然回车会产生一个字符,getchar会回收一个字符

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
bool a[105][105];
int main() {int i, j, n, m;char p;scanf("%d%d",&n,&m);for(i = 1;i <= n;i++) {getchar();for(j = 1;j <= m;j++) { scanf("%c",&p);if(p == '*')  { a[i][j] = 1; } } }for(i = 1;i <= n;i++) {for(j = 1;j <= m;j++) { if( a[i][j] == 1)  printf("*"); else { printf("%d",a[i+1][j+1]+a[i+1][j-1]+a[i+1][j]+a[i][j+1]+a[i][j-1]+a[i-1][j+1]+a[i-1][j]+a[i-1][j-1]);}     } printf("\n"); }return 0;
}

链表,字符串题,模拟与高精度相关推荐

  1. 模拟与高精度——字符串的展开

    模拟与高精度--字符串的展开 题目描述 输入格式 共两行. 第1行为用空格隔开的3个正整数,依次表示参数p1,p2,p3. 第2行为一行字符串,仅由数字.小写字母和减号"-"组成. ...

  2. 洛谷专题训练 ——【算法1-1】模拟与高精度

    洛谷题单[算法1-1]模拟与高精度 ACM-ICPC在线模板 题单链接: [算法1-1]模拟与高精度 下面的这一坨都是洛谷题单上的东东 题单简介 恭喜大家完成了第一部分语言入门,相信大家已经可以使用 ...

  3. (十三)真题模拟【告诉你答案是什么】

    真题模拟 面试真题 讲解前提示 何为变量提升 var和let const的区别 typeof返回哪些类型 列举强制类型转换和隐式类型转换 手写深度比较 isEqual 手写深度比较,模拟lodash ...

  4. 蓝桥杯 STEMA 考试 C++ 编程题模拟题

    蓝桥杯 STEMA 考试 C++ 编程题模拟题 该套题为蓝桥杯青少年创意编程组官方发布的考试白皮书上的模拟题. 初级组 编程题第一题 编程实现: 做统计. 输入 10 个正整数,以空格分隔.依次输出其 ...

  5. 蓝桥杯嵌入式STM32G431——第七届省赛真题模拟液位检测告警系统

    第七届省赛真题模拟液位检测告警系统 第七届省赛真题 主函数部分的代码功能实现(不包含各模块初始化代码) 第七届省赛真题 主函数部分的代码功能实现(不包含各模块初始化代码) #include " ...

  6. [AcWing]827. 双链表(C++实现)双链表模板题

    [AcWing]827. 双链表(C++实现)双链表模板题 1. 题目 2. 读题(需要重点注意的东西) 3. 解法 4. 可能有帮助的前置习题 5. 所用到的数据结构与算法思想 6. 总结 1. 题 ...

  7. 中国石油大学天梯赛真题模拟第四场

    中国石油大学天梯赛真题模拟第四场 L1-3 阅览室 (20 分) 天梯图书阅览室请你编写一个简单的图书借阅统计程序.当读者借书时,管理员输入书号并按下S键,程序开始计时:当读者还书时,管理员输入书号并 ...

  8. 数据结构 - 链表 - 面试中常见的链表算法题

    数据结构 - 链表 - 面试中常见的链表算法题 数据结构是面试中必定考查的知识点,面试者需要掌握几种经典的数据结构:线性表(数组.链表).栈与队列.树(二叉树.二叉查找树.平衡二叉树.红黑树).图. ...

  9. [XSY] 字符串题(字符串,构造)

    字符串题 考虑找到一种方法,能够对一个 lyndon 串 A ,直接求出 A 的下一个 lyndon 串. 考虑不断复制 A ,得 AAA-A 因为 lyndon 串是自身循环移位得到的串中字典序严格 ...

最新文章

  1. 计算机控制直流电机闭环调速实验,最小拍控制系统及直流电机闭环调速控制系统设计和实现实验报告...
  2. PHP电商的sku,tech| 关于电商系统中sku与spu的一个难题
  3. 钱穆的中学读书事(作者王国华)
  4. 他让全世界凶手睡不着觉,现实版福尔摩斯,退休了4次又被拽回来工作,无敌实在是太寂寞了~...
  5. os-enviroment
  6. 利用nginx集群式部署服务器中,数据同步问题
  7. python configure函数 循环_使用python统计git仓库中频繁修改的热点函数
  8. layer checkbox
  9. 小白跟学系列之手把手搭建NLP经典模型-2(含代码)
  10. 巧用 SSH 打通外网限制
  11. 移动磁盘提示使用驱动器中的光盘之前需要格式化文件怎么找回
  12. 软件测试(测试用例)—写用例无压力
  13. Newtonsoft 六个超简单又实用的特性【上下篇】
  14. Gilbert Elliot丢包模型
  15. ERD-ONLINE 2.0.3 免费在线数据库建模工具 正式发布
  16. 防火墙双机热备升级步骤
  17. 怎么注册Github?用手机2分钟完成注册,互联网就是互相连接
  18. Exchange 2003 设计与体系结构
  19. 所谓的不撞南墙不回头
  20. 半小时搞定Yolov5安装配置及使用(详细过程)

热门文章

  1. 【华为机试真题 Python实现】数组拼接
  2. routeros v6.43.2_配置自签名证书-RouterOS中级教程6
  3. 【日记本砸】21.05.08-17 重要的不是抢先别人跑多远,而是那种越跑越有劲的状态
  4. 节后上班第一天,我们为无心上班的你准备了一些硬科技“谈资”
  5. LINXU——命令的使用
  6. 【深度学习】tensorboard中的图片放到论文中
  7. Python 使用requests发送POST请求总结
  8. 自动拨号程序调试过程
  9. 【尚硅谷】Java数据结构与算法详细整理笔记(附代码)更新中…………
  10. RK3568、RK3588、RK3358性能介绍及表格差异性对比整理