9月10日360笔试编程题

本文介绍了两种编程问题:一是通过正向和反向字符串匹配来判断观察顺序的有效性;二是实现简单的内存管理功能,包括内存分配、释放及碎片整理。

最强大脑


题目描述:

把从N到M车站看到的旗帜颜色依次列出来,然后告诉你小B记得的旗帜颜色序列,判断小B究竟是从N和M之间哪些方向才能看到所说颜色的旗帜。


可能的结果有:

forward

backward

both

invalid


输入示例:

atob

a

b

aaacaaa

aca

aa


输出示例:

forward

both


思路:这题实际上是一个字符串匹配,对于第一个例子,如果a能在atob中找到,那再在atob的a之后去寻找b,如果b也找到了,那么forward=true。

             然后反向寻找,即在bota中找a和b,先找到a,然后再找b,但是在bota的a后面已经没有东西了,所以backward=false。


对于第二个例子,如果aca能在aaacaaa中找到,那再在aca之后找aa,如果找到了,那么forward=true

        然后反向选择,即在aaacaaa中寻找aca,然后找aa,也找到了,所以backward = true

        由于forward=true and backward= true,所以输出both


具体的程序也是一个模拟的过程:

#include <stdio.h>
#include <string.h>


char a[100002];
char b[100002];
char c[100002];


int main()
{
int n,m,l,i,j,k,flag1,flag2;
int forward,backward;
while (scanf("%s",&a)!=EOF)              //完整的字符串为a
{
scanf("%s",&b); //第一个字符串为b
scanf("%s",&c); //第二个字符串为c
n = strlen(a);
m = strlen(b);
l = strlen(c);
forward = 0;backward = 0;
i = 0;j = 0;k = 0; flag1 = 0;
while (i<n) 
{
while (i<n&&a[i]!=b[0]) i++; //先在完全的字符串中找到b的开头
while (j<m&&i<n&&a[i]==b[j]) { //进行匹配,直到两个字符串不相同
i++;j++;
}
if (b[j]=='\0') { flag1 = 1;break;} //如果b完全匹配完了,说明可以在a中找到b,flag1=true,继续在字符串a中找字符串c
else j = 0;
}
flag2 = 0;j = 0;
if (flag1) {
while (i<n)
{
while (i<n&&a[i]!=c[0]) i++; //先在完全的字符串中找到c的开头
while (j<l&&i<n&&a[i]==c[j]) { //进行匹配,直到两个字符串不相同
i++;j++;
}
if (c[j]=='\0') { flag2 = 1;break;} //如果c完全匹配完了,说明可以在a中找到c,flag2=true
else j = 0;
}
}
if (flag1&&flag2) forward = 1; //如果flag1=true和flag2=true,说明两个字符串b和c都可以在a中找到,所以forward=true


i = n-1;j = 0; flag1 = 0; //判断反向的情况
while (i>0) 
{
while (i>0&&a[i]!=b[0]) i--; //先在完全的字符串中找到b的开头,由于是反向,所以i从n-1开始遍历
while (j<m&&i>=0&&a[i]==b[j]) { //进行匹配,直到两个字符串不相同
i--;j++;
}
if (b[j]=='\0') { flag1 = 1;break;} //如果b完全匹配完了,说明可以在a中找到b,flag1=true,继续在字符串a中找字符串c
else j = 0;
}
flag2 = 0;j = 0;
if (flag1) {
while (i>0)
{
while (i>0&&a[i]!=c[0]) i--; //先在完全的字符串中找到c的开头
while (j<l&&i>=0&&a[i]==c[j]) {  //进行匹配,直到两个字符串不相同
i--;j++;
}
if (c[j]=='\0') { flag2 = 1;break;}          //如果c完全匹配完了,说明可以在a中找到c,flag2=true,说明forward=true
else j = 0;
}
}
if (flag1&&flag2) backward = 1;             //如果flag1=true和flag2=true,说明两个字符串b和c都可以在a中找到,所以backward=true
if (forward&&backward) printf("both\n"); //根据forward和backward的情况,一共有四种输出
else if (forward) printf("forward\n");
else if (backward) printf("backward\n");
else printf("invalid\n");
}
}




内存管理

有三种对内存的操作:

new size:分配size大小的内存块,返回该内存块的句柄(即编号

del handle:释放句柄handle指向的内存块

def:整理内存碎片,将所有已分配内存块按地址从低到高的顺序迁移,使空闲内存空间在高地址端拼接在一起。


思路:

用一个block数组记录已经申请的内存的起始地址和长度,开了一个mem数组标记已经分配的和没有分配的内存。
new操作的时候,增加block数组,记录起始位置和block的长度,然后将mem的对应位置由0改为1.
del操作,将对应的block数组起始位置置为-1,长度置为0,然后将mem的对应位置由1改为0.
def操作,这个操作我的思路有点不清晰,写得有点久,我最开始的想法是把block按照起始地址排序,然后组合起来,但是问题是block的下标是有用的,删除的时候会用到,所以排序的时候不能交换block的下标。最后使用的方式是扫描mem数组,然后找到第一个为1的地址,扫描这个是第几个block,然后把这个block前移。

具体代码:
#include <stdio.h>
#include <string.h>

struct Block{
int begin;
int length;
}; //记录每个内存块的起始地址和长度


int main()
{
int n,m;
int number,handler;
int flag;
char command[10];
int mem[10001];
Block block[10001];

handler = 0;
scanf("%d %d",&n,&m);
for (int i=1;i<=m;i++) mem[i]=0; //内存初始化为0
for (int i=0;i<n;i++)
{
scanf("%s",&command); //读入命令
if(!strcmp("def",command)==0)  //如果是new 和 del,还要读入操作数
scanf("%d",&number);
if (strcmp("new",command)==0) 
{
flag = 0;
int head = 1;
int len;
while (head<=m){
len = 0;
while (head<=m&&mem[head]) head++; //在mem数组中找到第一个不是1的位置,即未分配的内存
while (len<number&&mem[head]==0) {head++;len++;}//寻找空闲内存的长度
if (len==number) { //如果长度符合要求,记录在block数组中,并将mem数组中对应位置1
for (int i=head-len;i<head;i++) mem[i]=1;
handler++;
block[handler].begin=head-len;
block[handler].length = len;
printf("%d\n",handler);
flag = 1;
break;
}
}
if (!flag) printf("NULL\n"); //如果内存分配失败,输出NULL
}
if (strcmp("del",command)==0) {
if (block[number].begin==-1) printf("ILLEGAL_OPERATION\n"); //如果删除的内存块已经被删除了,输出"非法操作"
else {
for (int i=block[number].begin;i<block[number].begin+block[number].length;i++) //将mem数组中对应位置置0
mem[i]=0;
block[number].begin = -1;block[number].length = 0; //将对应block数组起始位置置为-1,长度置为0
}
}
if (strcmp("def",command)==0) { //内存整理
int h=1; //h用于记录整理过程中,当前空闲内存的起始位置,起始位置为1,每整理一段内存就后推
for (int i=1;i<=m;i++)
{
while (i<=m&&mem[i]==0) i++; //找到第一个内存的已分配位置
if (i>m) break; //如果已经遍历完内存,就退出
int j=1;
for (j=1;j<=handler;j++)
if (block[j].begin==i) break; //找到这是第几个block
if (j<=handler) { //如果找到了这个block
block[j].begin = h; //将这段内存放到h起始的空闲内存中
for (int k=h;k<h+block[j].length;k++) mem[k] = 1; //mem对应位置1
for (int k=i;k<i+block[j].length;k++) mem[k] = 0;//mem对应位置0,相当于从i开头的一段位置搬到了从h开头的一段位置上
h = h+block[j].length; //h往后推
}
}
}
}
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值