回文数和铺地毯思路讲解
文章目录
- 回文数和铺地毯思路讲解
- 前言
- 一.回文数
- 1.1思路分析
- 1.2转换函数
- 1.3计算求和
- 1.4进制转换计算
- 1.5回文数判断
- 二.铺地毯
- 2.1题目解释
- 2.2思路分析
- 2.3存放地毯信息
- 2.4判断排查点
- 三.源码
- 3.1回文数
- 3.2铺地毯
- 后言
前言
哈喽,各位小伙伴们大家好,好久不见,甚是想念。今天小编给大家带来两道题目的思路讲解(回文数和铺地毯)。这两道题目比较考察我们的数学思维能力,相信看完后,一定会对你的数学思维能力有所提升。接下来让我们进入正题!
一.回文数
1.1思路分析
不难看出,每一次STEP的步骤都是一样的,对上一次的数进行倒序后两数相加,在对求和数进行回文数判断。但要注意的是进制并非一定是10进制,所以还需进行进制转换计算。我们可以先创建两个函数,一个实现字符数转整数,另一个实现整数转字符数。之后创建一个字符数组存放第一次的判断数(M),对数据进行转换为整型后创建一个二维数组存放正序数,进行逆序后,存放逆序数。在创建一个整型数组存放10进制状态下正逆数据的求和数,之后对数组的每个元素进行进制转换计算,得出N进制的求和数,在进行回文数判断即可。是回文数就输出,不是就继续循环,记录循环次数。
1.2转换函数
字符数和整数间的转换可以利用ASCLL码值的知识,字符进行计算时,其实就是用控制字符的ascll值进行计算。注意当大于十进制时,我们用字符A代表数字10,B代表数字11,以此类推。我们掌握这个知识点后就可以写出转换函数了(这篇文章有提到如何用ASCLL值进行字符和整数转换)
int changes(char a)//字符数变整数
{
int y;
if (a <= '9')
y = a - '0';//10进制以下的数减去字符'0'的ascll即可
else
y = a - 'A' + 10;//10进制'A'代表10,'B'代表11,以此类推。'A'-'A'+10=0+10=10
return y;
}
char change(int a)//整数变字符数
{
int y;
if (a <= 9)
y = a + '0';//由上面推导,加减调换即可在字符数和整数间互相转换
else
y = a - 10 + 'A';
return y;
}
1.3计算求和
先用strlen(需要包含头文件include<string.h>)求出长度(有几位数),再对字符数组调用转换函数后存入一个两列二维数组的第一列,再将第一列数据倒序存入第二列。之后创建一个整形数组,for循环遍历二维数组,将每行的两个数的求和数存入数组。注意这个时候的求和数是10进制相加得来的,并不是题目要求的N进制,所以我们还需要进行进制转换计算。
int main()
{
int sum = 0;
int k = 0;
int c = 0;
int a;
int b = 0;//创建需要准备的变量
int fl = 2;//判断循环是否结束
scanf("%d\n", &a);
char a1[100];//正序字符数组,接收字符数字
scanf("%s", a1);
b = strlen(a1);//统计字符串长度
int a2[2][100];//整形二位数组,存放正序整形数字,和逆序整形数字,方便求和
int a3[100];//求和数组,存放每次正逆序求和结果
while (fl == 2)
{
c++;//统计STEP步骤次数
for (int i = 0; i < b; i++)
{
a2[0][i] = changes(a1[i]);//字符数转整数
}
for (int i = b - 1; i >= 0; i--)
{
a2[1][i] = a2[0][b - 1 - i];//存放逆序数组(倒序)
}
for (int i = 0; i < b; i++)
{
a3[i] = a2[0][i] + a2[1][i];//存放求和结果
}
1.4进制转换计算
为了避免计算后出现进位(1+99=100,99由两位数变成三位数就是进位)情况导致数组无法存放(因为首位数字是放在数组的[0]),我们需要对数组后移一位。之后我们对每位数进行**%N取余**,再用一个变量记录进位数(/N)。得到转换后的求和数后,我们还需要对进位情况判断,如果不进位 ,我们需要将求和数前移一位。
int a4[100] = { 0 };//创建新数组来对求和数进行进制计算
for (int i = 0; i < b; i++)
{
a4[i + 1] = a3[i];//进制后可能会进位,所以后移数据,留一个进位空间(留给求和数都第一个数字)
}
int k = 0;//进位数
char a5[100] = { 0 };//存放进制计算后的数(真正的求和数)
for (int i = b; i >= 0; i--)
{
a5[i] = change((a4[i] + k) % a);//%a取余计算每一位数
k = (a4[i] + k) / a;///a计算向下一位进位多少
}
if (a5[0] == '0')//判断是否比原来多进一位,如果是那就继续后移一位,不是就前移一位
{
for (int i = 0; i <= b; i++)
{
a5[i] = a5[i + 1];//向前移动一位
}
b -= 1;//如果没有进位那右指针作为下标就要比原来的数组长度小一
}
1.5回文数判断
我们先创建两个变量作为左右指针(数组下标),用for循环遍历数组,每次循环左右指针前后移动,直到指针相遇则判断完成。如果左右数组元素不同则用fl(变量)作标记,退出循环。 用if判断是否回文,是就结束循环并输出,不是就用for循环遍历将求和数赋值给字符数组,srtlenf赋值给b,继续下一次循环直到找到循环数,如果29次循环后还找不到回文数则按题目输出结束(因为包括30次,就算第30次是回文数也按题目输出)。
int letf = 0;
int right = b;//左右指针作为下标,进行回文数判断
while (letf <= right)
{
if (a5[letf] != a5[right])
{
fl = 1;//不是回文数做标记
break;
}
letf++;
right--;//指针移动,前后判断
}
if (fl == 1)
fl = 2;//不是回文数,fl==2,继续循环
else
{
printf("STEP=%d", c);//是回文数,输出
break;//结束循环
}
if (c == 30)
{
printf("Impossible!");//到达30步未找到回文数,输出
break;//结束循环
}
b = strlen(a5);//不是回文数继续循环,把求和数当成下一次循环的数,计算长度赋值给b
for (int i = 0; i < b; i++)
{
a1[i] = a5[i];//求和数赋值后进行下一次循环
}
}
return 0;
二.铺地毯
2.1题目解释
题目有点长,我给大家写了图解大家可以对照样例看一下。不同颜色的大宫格代表不同的地毯,题目排查坐标为2 2。大家看图可以发现坐标方格为编号3,所以输出3,如果坐标为空白方格就要输出-1。
2.2思路分析
大家很容易想到用一个二维数组记录每个方块的信息来做,但是如果数据很大的话二维数组占用的内存就会很大,所以不可取。那我们该如何记录地毯信息呢?其实很简单,获取每个地毯的输入信息后我们就可用数据算出地毯的横坐标范围和纵坐标范围了,只要判断输入的排查坐标是否在两个范围内,就可以知道是否在该地毯上了。如果每行数据都判断不在,那就是不在地毯上输出-1。如何计算范围大家可以看一下图解。
2.3存放地毯信息
我们先创建一个五列的二维数组,存放地毯的四个数据和该地毯的编号,并且记录地毯数。
int p[10000][5] = { 0 };//创建数组存放数据
int n = 0;
scanf("%d", &n);//接收地毯数
int c = 0;//数组下标
int v = 1;//地毯编号
for (int i = 0; i < n; i++)
{
int a, b, g, k;
scanf("%d%d%d%d", &a, &b, &g, &k);
p[c][0] = a;
p[c][1] = b;
p[c][2] = a + g - 1;
p[c][3] = b + k - 1;
p[c][4] = v;
v++;
c++;//地毯数增加,下标移动
}
2.4判断排查点
但是有些方块会被多个地毯覆盖,我们需要的是最上面地毯(最晚记录)的编号,所以我们用for循环从数组的后面往前遍历(这样能保证匹配成功的是最上面的地毯),判断排查点是否在计算范围即可,排查点所有数据范围都不符合就输出-1。
int e, r;
scanf("%d%d", &e, &r);//接收排查点坐标
int fl = 0;//标记判断是否为覆盖点
for (int i = c - 1; i >= 0; i--)
{
if (p[i][0] <= e && p[i][2] >= e && p[i][1] <= r && p[i][3] >= r)//判断坐标是否在覆盖区范围内
{
printf("%d", p[i][4]);//输出地毯编号
fl = 1;//标记
break;//结束循环
}
}
if (fl == 0)//判断坐标是否在覆盖区范围内,不在就输出-1
printf("%d" ,-1);//输出
三.源码
3.1回文数
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<math.h>
#include<string.h>
int changes(char a)//字符数变整数
{
int y;
if (a <= '9')
y = a - '0';//10进制以下的数减去字符'0'的ascll即可
else
y = a - 'A' + 10;//10进制'A'代表10,'B'代表11,以此类推。'A'-'A'+10=0+10=10
return y;
}
char change(int a)//整数变字符数
{
int y;
if (a <= 9)
y = a + '0';//由上面推导,加减调换即可在字符数和整数间互相转换
else
y = a - 10 + 'A';
return y;
}
int main()
{
int sum = 0;
int k = 0;
int c = 0;
int a;
int b = 0;//创建需要准备的变量
int fl = 2;//判断循环是否结束
scanf("%d\n", &a);
char a1[100];//正序字符数组,接收字符数字
scanf("%s", a1);
b = strlen(a1);//统计字符串长度
int a2[2][100];//整形二位数组,存放正序整形数字,和逆序整形数字,方便求和
int a3[100];//求和数组,存放每次正逆序求和结果
while (fl == 2)
{
c++;//统计STEP步骤次数
for (int i = 0; i < b; i++)
{
a2[0][i] = changes(a1[i]);//字符数转整数
}
for (int i = b - 1; i >= 0; i--)
{
a2[1][i] = a2[0][b - 1 - i];//存放逆序数组
}
for (int i = 0; i < b; i++)
{
a3[i] = a2[0][i] + a2[1][i];//存放求和结果
}
int a4[100] = { 0 };//创建新数组来对求和数进行进制计算
for (int i = 0; i < b; i++)
{
a4[i + 1] = a3[i];//进制后可能会进位,所以后移数据,留一个进位空间(留给求和数都第一个数字)
}
int k = 0;//进位数
char a5[100] = { 0 };//存放进制计算后的数(真正的求和数)
for (int i = b; i >= 0; i--)
{
a5[i] = change((a4[i] + k) % a);//%a取余计算每一位数
k = (a4[i] + k) / a;///a计算向下一位进位多少
}
if (a5[0] == '0')//判断是否比原来多进一位,如果是那就继续后移一位,不是就前移一位
{
for (int i = 0; i <= b; i++)
{
a5[i] = a5[i + 1];//向前移动一位
}
b -= 1;//如果没有进位那右指针作为下标就要比原来的数组长度小一
}
int letf = 0;
int right = b;//左右指针作为下标,进行回文数判断
while (letf <= right)
{
if (a5[letf] != a5[right])
{
fl = 1;//不是回文数做标记
break;
}
letf++;
right--;//指针移动,前后判断
}
if (fl == 1)
fl = 2;//不是回文数,fl==2,继续循环
else
{
printf("STEP=%d", c);//是回文数,输出
break;//结束循环
}
if (c == 30)
{
printf("Impossible!");//到达30步未找到回文数,输出
break;//结束循环
}
b = strlen(a5);//不是回文数继续循环,把求和数当成下一次循环的数,计算长度赋值给b
for (int i = 0; i < b; i++)
{
a1[i] = a5[i];//求和数赋值后进行下一次循环
}
}
return 0;
}
3.2铺地毯
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int p[10000][5] = { 0 };//创建数组存放数据
int n = 0;
scanf("%d", &n);//接收地毯数
int c = 0;//数组下标
int v = 1;//地毯编号
for (int i = 0; i < n; i++)
{
int a, b, g, k;
scanf("%d%d%d%d", &a, &b, &g, &k);
p[c][0] = a;
p[c][1] = b;
p[c][2] = a + g - 1;
p[c][3] = b + k - 1;
p[c][4] = v;
v++;
c++;//地毯数增加,下标移动
}
int e, r;
scanf("%d%d", &e, &r);//接收排查点坐标
int fl = 0;//标记判断是否为覆盖点
for (int i = c - 1; i >= 0; i--)
{
if (p[i][0] <= e && p[i][2] >= e && p[i][1] <= r && p[i][3] >= r)//判断坐标是否在覆盖区范围内
{
printf("%d", p[i][4]);//输出地毯编号
fl = 1;//标记
break;//结束循环
}
}
if (fl == 0)//判断坐标是否在覆盖区范围内,不在就输出-1
printf("%d" ,-1);//输出
return 0;
}
后言
这两道题还是挺经典的,比较考察我们的数学思维,希望看完大家能有所收获。好啦,今天就分享到这里啦!拜拜,各位帅哥美女!