【蓝蓝计算机考研算法】-day03小球反弹到最终静止共走的距离&我要通过

758 阅读6分钟

5.一个小球从10处落下,每次的弹回之前的高度一半,

请问小球在静止之前一共走过多少距离?

思路

利用循环进行求距离,注意要加上原始的高度。更新值时,用它值本身。

具体实现

#include<stdio.h>
float Desin() {
	float sum=0,b;//统计共走的距离,b是每次除后的高度
	float high=10;//是初始时的高度
	while(high!=0) {
		b = high / 2;//每次落下高度的一半
		sum += b+high;//累加走的距离
		high = high / 2;//更新high的值(方法积累:重点注意下,下次重复这样的可参考)
	}
	return sum;
}
int main(){
	printf("小球静止时候一共走了%f米", Desin());
}

运行结果

小球静止时候一共走了29.999998

复杂度分析

复杂度分析若分析错,请帮忙看出的大神帮忙指点,这一块很是薄弱。

时间:循坏次数主要与高度有关,高度/2约等于就是高度。所以时间复杂度为O(n),n为高度。 空间:没有用到递归或者是引用额外的数组存储,所以空间复杂度为O(1);

6.我要通过

“答案正确” 是自动判题系统给出的最令人欢喜的回复。本题属于PAT的“答案正确”大派送——只要读入的字符串满足下列条件,系统就输出"“答案正确”,否则输出“答案错误”。

得到“答案正确”的条件是:

1.字符串中必须仅有P、A、T这三种字符,不可以包含其它字符;

2.任意形如xPATx的字符串都可以获得“答案正确”,其中x或者是空字符串,或者是仅由字母A组成的字符串:

3.如果aPbTc是正确的,那么aPbATca也是正确的,其中a、b、c均或者是空字符串,或者是仅由字母A组成的字符串

现在就请你为PAT写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。

输入格式:

每个测试输入包含1个测试用例。第1行给出一个正整数n(≤10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过100,且不包含空格。

输入样例:
10
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
APT
APAATTAA

输出格式:

每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出YES,否则输出NO

输出样例:
YES
YES
YES
YES
NO
NO
NO
NO
NO
NO

思路

条件2表示 ,只有三个字母,分别是P、A、T时候是正确。
条件2表示,在PAT的前后加上相同个数的A或者不加时正确的。如AAAPATAAA
条件3表示,aPbTc正确,那在PT中间加入一个A,最前边和后边也要分别加入一个A。此处的a、b、c理解为占位符号,他们可以代表A或者是空字符即没有。

总的来说可分为:

1.前后无A型,中间有无数A正确 (相对于P和T来说)
2.前后有A型,后A=前A* 中A
根据条件一知当字符个数小于3时,回答错误。接下来讨论个数大于3个时候。
字符个数大于三个时
1.记录P、T个数及它们在字符串中最后出现的位置。用other表示除P、A、T三个字符外的字母个数。
2.P和T的个数只有一个时正确。要没有其他字符,所以other要不等于0;(local_T - local_P)表示中间没有数字或者是PT位置相反时候。
3.利用 后A=前A*中A做最后的判断。

具体实现

#include<stdio.h>
#include <string>
#include <iostream>
#include<cstdio>
using namespace std;

//1.前后无A  PAT  PAAAT
//2.前后有A,后A=前A*中A   APATA   APAATAA
int main() {
	int num;//循坏次数
	printf("请输入需要检测的字符串个数\n");
	scanf_s("%d", &num);
	while (num--) {
		char str[201];//定义一个字符数组
		str[200] = '\0';//解决strlen(str)的边界警告处理,将最后一位复制为结束;可不用
		//printf("请输入需要检测的字符串\n");
		scanf_s("%s", str, 201);	
		int num_P = 0, num_T = 0,other = 0;//num_P表示P的个数,num_T表示T的个数,other表示除了P、A、T三个字符外的的字符个数
		int local_P = -1, local_T = -1;//local_P最后一个P的位置,local_T最后一个T的位置
		//字符个数小于3时
		if (strlen(str) < 3) {
			printf("NO\n");
			continue;//结束本次循环
		}
		//字符个数大于3时,对P、A、T分别计算其个数
		for (int i = 0; i < strlen(str); i++) {
			if (str[i] == 'P') {
				num_P++;
				local_P = i;//记录P的最后一个位置
			}
			else if (str[i] == 'T') {
				num_T++;
				local_T = i;
			}
			else if (str[i] != 'A') {//除了A之外别的字符,
				other++;
			}
		}
		//P和T的个数只有一个,要没有其他字符,所以other要不等于0;(local_T - local_P)中间没有数字或者是PT位置相反时候
		if (num_P != 1 || num_T != 1 || other != 0|| (local_T - local_P)<=1) {
			printf("NO\n");
			continue;
		}
		//APAATAA 后A=前A*中A
		//before_x为P前面A的个数,middle_x为P和T之间的个数,back_x为T到字符串结果的个数
		int before_x = local_P, middle_x = local_T - local_P-1, back_x = strlen(str) - local_T - 1;
		if (back_x - before_x * (middle_x - 1) == before_x) {
			printf("YES\n");
		}
		else {
			printf("NO\n");
		}
	}
	return 0;
}

运行结果

请输入需要检测的字符串个数
10
PAT
YES
PAAT
YES
AAPATAA
YES
AAPAATAAAA
YES
xPATX
NO
PT
NO
WHatever
NO
APPAATAA
NO
APT
NO
APAATTAA
NO

复杂度分析

时间:外层while循环n次,内for也要循环m次,所以时间复杂度为O(n*m); 空间:用到了char的字符数组,因此空间复杂度为数组的大小O(n);

总结

简单的题目有思想,也无法用代码写出来,困难的题目还在是毫无头绪,之前的学习又全部还回去了。

今日收获,学到了scanf() 的用法:scanf这个函数有隐患,所以VS建议使用他们自己开发的scanf_s,如果你要用scanf要去VS里面配置一下。
字符串的输入定义需要用char,而不是string(string是个类对象不能用scanf输入的)。
字符串输入用 %s,而c里面的字符串是char[],用c语音写就要先声明一个char[]

解决C语言的scanf_s()函数问题

本篇代码使用编辑Visual Studio 2022,在使用字符串的输入时报错。因此查阅资料得以解决,资料来源:blog.csdn.net/qq_43309823…

为什么现在要用scanf_s()?

从vc++2005开始,VS系统提供了scanf_s()。在调用该函数时,必须提供一个数字以表明最多读取多少位字符。
很多带“_s”后缀的函数是为了让原版函数更安全,传入一个和参数有关的大小值,避免引用到不存在的元素,有时黑客可以利用原版的不安全性黑掉系统。比如:char d[20];写成scanf_s("%s",d,20);才是正确的,有这个参数20使准确性提高。(百度百科)

如何使用scanf_s()

输入整型时候:

//以下代码没有测试出:结果为2,因为输入两个数a和b
	int i, b;
	int result;//函数返回值
	scanf_s("%d", &i);
	scanf_s("%d %d", &i, &b);
	result = scanf_s("%d %d", &i, &b);
	printf("%d", result);

这是我运行的结果:若有什么地方错误,请大神指出,我没有得出代码内的注释内容; image.png

字符的时候,scanf_s()的安全性就体现出来,:

char d, e[80];
scanf_s("%c %s", &d,1, &e,80);//字符c输入1个,d后面跟1;e字符数组80个,所以e后面加80