中国MOOC大学-周强-数据结构与算法实战-2019-09-PAT习题集(辛酸解题过程,学习笔记一)

写在前面的话:
CSDN博客没开几天,要好好学习了。
我在中国mooc上选了周强老师的课程,这里进行一下总结,以备后面查看学习。
前面有几个写的题解,这里不想再重新弄了,链接放这了。

F1 提桶寻宝

F2 判断回文

例-1 大炮打蚊子 (15 分)

例-2 后缀式求值 (25 分)

例-3 简单模拟单队列排队 (20 分)

F3 查找数组元素最大值 (10 分)

本题要求实现一个函数,查找数组中最大元素的下标。例如数组为{1,3,5,7,9},则该函数应该返回4。题目输入保证数组元素各不相同。

函数接口定义:

int indexOfMax(int *array, int size);

其中 array 和 size 是用户传入的参数。 array 是数组首地址; size 是数组元素的个数。函数须返回数组中最大元素的下标(从0开始)。

裁判测试程序样例:

  /* 此测试程序仅为示例,实际的测试程序可能不同 */
    #include 
    #define MAXSIZE 100
    int indexOfMax(int *array, int size);
    int main(){
        int num[MAXSIZE];
        int total;
        scanf("%d",&total);
        for(int i=0; i

输入样例:

4 2016 2017 1999 1998

输出样例:

2017

解题:

int indexOfMax(int *array,int size)
{
	int max=array[0],indexOfMax = 0;
	int i;
	
	for(i=1;i max)        //大于最大值要进行交换 
		{
			max = array[i];
			indexOfMax = i;
		}
	return indexOfMax;
} 

简单题不多说。

——————————————————————————————————————

F4 数组逆转 (10 分)

本题要求实现一个函数,可将一个整型数组里的元素逆转。例如原数组是[1,3,5,7,9],逆转之后变成[9,7,5,3,1]

函数接口定义:

void reverse(int *array, int size);

其中参数 array是数组首地址,size是数组的长度(size>0)。

裁判测试程序样例:

函数被调用进行测试的一个可能的例子像这样:
#include 
void reverse(int *array, int size);
int main()
{
    int n;
    scanf("%d", &n);
    int array[n];
    for(int i=0; i

输入样例:

5
1 2 3 4 5

输出样例:

5 4 3 2 1

解题:

void reverse(int *array, int size)
{//数组元素怎么逆转啊?最笨的方法是,我申请一个跟array一样大的数组呗,从一个到另一个换呗 
	if(size<2) return ;	
	else
	{
		int b[size];
		int i;
		for(i=0;i

函数题,这里是申请了一个数组,没有考虑到更好的方法,就是不申请内存的数组逆转;这里练习用也可以啦。

—————————————————————————————————————————

P1 N进制高精度加法 (20 分)

到底应该怎样理解进制呢?首先得有“一个”的数量概念,然后就是这样的:
把用来表示数量的符号依次排列,例如: q w e r
然后定义最前面的符号为“零”,即“没有”,后面的符号表示的数量依次比前一个符号多“一个”
进制就这样产生了: 例如当我们数数,依次数到 q w e r ,再往后数一个,符号不够用了,那么就写成 wq
并且,我们把这种进制命名为“wq”进制。
感觉怪异吗? 那么请换成我们熟悉的所谓“10”进制看看:
我们的用于表示数量的符号依次是: 0 1 2 3 4 5 6 7 8 9 , 当数到9,再往后数“一个”时,就数到了 10
看这幅漫画(来源于网络),看看能不能理解“进制”的概念?中国MOOC大学-周强-数据结构与算法实战-2019-09-PAT习题集(辛酸解题过程,学习笔记一)_第1张图片
现在,给定表示数量的符号(这些符号就形成了某种进制),以及该种进制下的两个不超过100位的正整数,请计算两数之和。

输入格式:

第一行给定表示数量的符号,每个符号为一个字符、各不相同且中间没有空格,最多有30个符号且符号的可能范围是:数字0-9、大小写字母、!@#$%^&*()
接下来两行每行给出一个该进制下的不超过100位的正整数

输出格式:

在一行中输出该进制下的两数之和。

输入样例1:

0123456789
123
12

输出样例1:

135

输入样例2:

abcd
bcd
bc

输出样例2:

cab

解题:

思路:
我把每个字符所代表的数字记下来, 0,1,2,3,其实就是下标了;然后把它转换成数字,再按照加法相加,最后再还原成所用的符号不就可以了?

  • 在这里面,我定义了一个函数,int findIndex(string str, char c) 用来找特定字符c在str中的下标,也就是代表数字是几啦;

  • 接着,是相加函数,int add(int a[],int lenOfa,int b[],int lenOfb, int max,int sum[]),这里主要注意的就是要进位的问题;

  • 最后,输出相应的字符串,对应的下标输出;

代码:

#include
#include
#include
using namespace std;
/*
* 我把每个字符所代表的数字记下来, 0,1,2,3,其实就是下标了;然后把它转换成数字,再按照加法相加,最后再还原成所用的符号不就可以了? 
*/
int findIndex(string str, char c)
{
	int index = -1;
	for(int i=0;i=0; i--)
	{
		index = findIndex(str,Tocstr[i]);
		if(index>=0)
		{
			a[Tocstr.length()-1 - i] = index;
		//	printf("index = %d a[%d] = %d\n",index,str1.length()-1 - i ,index);	
		}	
	} 
}
int add(int a[],int lenOfa,int b[],int lenOfb, int max,int sum[])
{
	int i;
	int tem;
	int len = lenOfa > lenOfb ? lenOfa+1 : lenOfb +1;
	for(i=0;i <=len;i++)sum[i] = 0; //sum全部清零 
	 
	for(i = 0 ; i=max)
			{
				sum[i+1]++;
				sum[i] -=max;
			}
			
		} 
		else
		{
			sum[i+1]++;
			sum[i] =sum[i] + tem - max; 
		}
	//	printf("第 %d 次 :sum[%d] = %d,max =%d \n",i,i,sum[i],max);
	}

	while(i=max)
		{
			sum[i+1]++;
			sum[i] -= max;
		}
	//	printf("第 %d 次 :sum[%d] = %d,max =%d \n",i,i,sum[i],max);
		i++;
	}
	while(i=max)
		{
			sum[i+1]++;
			sum[i] -= max;
		}
	//	printf("第 %d 次 :sum[%d] = %d,max =%d \n",i,i,sum[i],max);
		i++;
	}
	if(sum[i]>0) return i+1;
	else return i;
	
}
int main()
{
	string str;
	getline(cin,str);  //获得进制数 
	int max = str.length(); //算得是几进制数 
	int index ; 
	string str1,str2;
	string sum;
	
	int num1[102],num2[102];
	int sum1[102];
	
	getline(cin,str1);  //输入两个加数,我们这里假定输入没有错误 
	getline(cin,str2);
	
	changeStrToNum(str1,str,num1);
	changeStrToNum(str2,str,num2);
//	for(int i=0;i=0;i--)printf("%c",str[sum1[i]]); 
	printf("\n");
	return 0;
}

P2 九宫格输入法 (15 分)

假设有九宫格输入法键盘布局如下:

 [ 1,.?! ] [ 2ABC ] [ 3DEF  ]
 [ 4GHI  ] [ 5JKL ] [ 6MNO  ]
 [ 7PQRS ] [ 8TUV ] [ 9WXYZ ]
           [ 0空  ]

注意:中括号[ ]仅为了表示键盘的分隔,不是输入字符。每个中括号中,位于首位的数字字符即是键盘的按键,按一下即可输入该数字字符。多次按同一个键,则输入的字符依次循环轮流,例如按两次3,则输入D;按5次7,则输入S;按6次2,则输入A。按键0的输入组合是0和空格字符,即按两次0输入空格。

你需要对于给定的按键组合,给出该组合对应的文本。

输入格式:
输入在一行中给出数个字符的按键组合(例如 999 表示按3次9),每个字符的按键组合之间用空格间隔,最后一个输入法组合之后以换行结束。输入数据至少包括一个字符的按键组合,且输入总长度不超过500个字符。

输出格式:
在一行中输出该按键组合对应的文本。

输入样例:

22 5555 22 666 00 88 888 7777 4444 666 44

输出样例:

ALAN TURING

解题

#include
#include
#include

using namespace std;

 char p[10][5]={ {'0',' '},{'1',',','.','?','!'}, {'2','A', 'B','C'},
 {'3','D','E','F' },{'4','G','H','I'},{'5','J','K','L'},{'6','M','N','O'},
 {'7','P','Q','R','S' },{'8','T','U','V'},{'9','W','X','Y','Z'}};
 
 int main()
 {
 	string str;
 	getline(cin,str);
 	int a[10]; //用于计数
 	int tem;
	for(int i=0;i= '0' && str[i] <='9')
		{
			tem = str[i++] - '0';
			a[tem] = 1;
			while(i

P3 五子棋赢了吗?(简易判断) (15 分)

假设五子棋的棋盘是N * N的(正整数N<20),黑子用*表示,白子用#表示,空位置用. 表示。
现给你一个棋局,请判断黑子是否获胜,如获胜,显示Win,并给出获胜排列的最左边那列的最上方那颗棋子的坐标。(棋盘左上角坐标是 (0, 0) ,右下角坐标是 (N-1, N-1))
如果未获胜,则显示“Not yet”。
注意:

不考虑白子是否获胜以及棋子个数与黑子是否匹配,只考虑黑子排列。
为简化计算,不用考虑“活四”、“四三连”、“长连”、“三三连”等获胜或禁手条件,只判断黑子有5个(或更多)排成一条直线,包括横线、竖线或斜线为胜利条件。
输入保证最多只出现一处黑子胜利的排列,不需要考虑有多处排列时如何判断最左位置。
输入格式:
第一行是正整数N(N<20),接下来是表示棋盘排列的N行字符,每行有N个*或#或.字符。

输出格式:
若黑子(用*表示)获胜,打印一行字符,依次是 Win X Y ,其中X Y是黑子获胜排列的最左边那列的最上方的一颗棋子的坐标,X表示横坐标,Y表示纵坐标。
若黑子未获胜,打印一行: Not yet 。

输入样例1:

6
.***..
..#...
..#...
......
....*.
.....*

输出样例1:

Not yet

输入样例2:

7
..#....
..#....
..#..*.
..#.*..
..#*...
..*..##
.*.****

输出样例2:

Win 1 6

解题:

#include

#define Max 20

char qipan[Max][Max];
bool isWin(char qipa[][Max],int N,int firstx,int firsty,char w) //N*N棋盘,起始位置(x,y),棋子是w,判断该点是否可赢
{
	if(qipa[firstx][firsty] != w) return false;
	int count;
	int i,j;
	if(firsty + 4 < N && firstx - 4 >=0) //向右上搜索 
	{
		count = 0;
		for(i=firstx,j=firsty;i >= firsty -4 ,j <= firstx + 4;i--,j++)
		{
				if(qipa[i][j] != w ) break;
				else count++;
		} 
		if(count == 5) return true;
	}
	
	if(firsty + 4 < N)        //向右搜索 
	{
		count = 0;
		for(i=firstx,j=firsty;i <= firstx + 4,j <= firsty + 4;j++)
		{
				if(qipa[i][j] != w ) break;
				else count++;
		} 
		if(count == 5) return true;
	}
	
	if(firstx + 4 < N && firsty + 4 < N) //向右下搜索 
	{
		count = 0;
		for(i=firstx,j=firsty;i <= firstx + 4,j <= firsty + 4;i++,j++)
		{
				if(qipa[i][j] != w ) break;
				else count++;
		} 
		if(count == 5) return true;
	}
	
	if(firstx +4 < N)
	{
		count = 0;
		for(i=firstx,j=firsty;i <= firstx + 4;i++) //向下搜索 
		{
				if(qipa[i][j] != w ) break;
				else count++;
		} 
		if(count == 5) return true;	
	} 
	return false;
} 
int main()
{
	int N;
	scanf("%d",&N);
	getchar();
	//棋盘输入; 
	for(int i=0;i=0) 不然的话,格子不够多,咋下也赢不了 
  向右的,要考虑;(i,j+1);      (i,j+4

P4 打死我也不说! (20 分)

梗:最好的密电码是啥? 是“打死我也不说!”这样,即使帮我们传送密电码的猪队友被敌人抓住严刑拷打,我们也不用担心泄露秘密。

现在稍微改进一下,我们把“打死我也不说”的拼音首字母“DSWYBS”藏在一个矩阵里,而代表“打”的字母D和代表“说”的字母S所在的行列下标之和即是密码。

对于给定的矩阵,请判断其中是否藏有“DSWYBS”,如果有,给出首末两个字母的下标并计算密码;如果没有,打印一行“DSWYBS”。

注意:

  • 若藏有“DSWYBS”,则这串字母必是沿行、列或斜45度方向依次排列的。

  • 题目保证输入的矩阵至多藏有一串“DSWYBS”。

  • 矩阵左上角下标为(0,0)。

  • 区分大小写。
    题目保证输入的矩阵不含有类似这样的排列(即:仅有DSWYB五个字母,但是字母B与S相邻,可组成DSWYBS的排列 ) :

    DSB
    WY

输入格式:

第一行给出两个整数M、N(均不大于15、不小于4),接下来M行,每行有N个字母或数字,以换行结束。

输出格式:

如果输入矩阵中藏有“DSWYBS”,则输出三行,第一行和第二行分别是首字母D的下标和末字母S的下标,先行下标后列下标,以一个空格间隔。第三行给出两个字母四项下标值之和。

如果没藏有该串字母,则打印一行“DSWYBS”

输入样例1:

8 10
0x00z000d0
00aD00s000
00b0SWk000
000wcY000s
00000B0000
0000S00000
0000000000
0000000000

输出样例1:

1 3
5 4
13

输入样例2:

5 5
12345
adswa
54321
dswys
aaaaa

输出样例2:

DSWYBS

解题

#include

#define Max 15

char pwd[Max][Max];

bool findx(char pwd[][Max],int M,int N,int x,int y,int *secx,int *secy,char c) // 在指定位置查找下一个字符c的位置,并返回; 
{
	if(y>0 && pwd[x][y-1] == c) //左 
	{
		*secx=x;
		*secy=y-1;
		return true;
	}
	 
if(x>0 && y>0 && pwd[x-1][y-1] == c) //左上 
{
	*secx = x-1;
	*secy = y-1;
	return true;
}

if(x>0 && pwd[x-1][y] == c) //上
{
	*secx = x-1;
	*secy = y;
	return true;
} 

if(y+10 && pwd[x+1][y-1] == c)
{
	*secx = x+1;
	*secy = y-1;
	return true; 
}
return false;
}

int main()
{
	int M,N;
	scanf("%d%d",&M,&N);

getchar();
//输入矩阵 
for(int i=0;i

P5 切分表达式——写个tokenizer吧 (20 分)

[先说点出题背景]

这个题是为低年级同学、学C语言的同学准备的,因为,对这部分同学,这个题目编写起来略有一点复杂。如果是高年级、学过了正则表达式(Regular Expression)的同学或者学过了Java等OO语言的同学做这个题,应当发现这题比较简单吧。哦,对了,什么是tokenizer?请自行查询解决。反正在此处不应翻译成“令牌解析器”。

[正题]

四则运算表达式由运算数(必定包含数字,可能包含正或负符号小数点)、运算符(包括+、-、*、/)以及小括号((和))组成,每个运算数、运算符和括号都是一个token(标记)。现在,对于给定的一个四则运算表达式,请把她的每个token切分出来。题目保证给定的表达式是正确的,不需要做有效性检查。

输入格式:
在一行中给出长度不超过40个字符的表达式,其中没有空格,仅由上文中token的字符组成

输出格式:
依次输出表达式中的tokens,每个token占一行。

输入样例:

32*((2-2)+5)/(-15)

输出样例:

32
*
(
(
2
-
2
)
+
5
)
/
(
-15
)

解题

#include
#include
#include
#include
#include

using namespace std;

stack s;
queue q;

int main()
{
	string str;
	getline(cin,str);
	for(int i =0;i = '0' && str[i] <='9')
		{
			printf("%c",str[i++]);
			while(i= '0' && str[i] <='9')||str[i]=='.')printf("%c",str[i++]);
				else
				{
					i--;
					break;
				}
			}
			printf("\n");
		}
		else if(str[i] == '-'|| str[i] == '+')
		{
			if((str[i-1]>= '0' && str[i-1] <='9')||str[i-1]==')')  //减号
			{
				printf("%c\n",str[i]); 
			}
			else printf("%c",str[i]); //负号 
		}
		
		else printf("%c\n",str[i]); 
	}
	return 0;
		
} 

你可能感兴趣的:(数据结构与算法实战)