60、计算网络信号
题目
网络信号经过传递会逐层衰减,且遇到阻隔物无法直接穿透,在此情况下需要计算某个位置的网络信号值。注意:网络信号可以绕过阻隔物
array[m][n],二维数组代表网格地图
array[i][j]=0,代表i行j列是空旷位置
array[i][j]= x,(x为正整数)代表i行j列是信号源,信号强度是x,
array[i][j]=-1, 代表i行j列是阻隔物
信号源只有1个,阻隔物可能有0个或多个;
网络信号袁减是上下左右相邻的网格衰减1现要求输出对应位置的网络信号值。
输入
输入为三行,
第一行为 m、n,代表输入是一个mxn 的数组,
第二行是一串 mxn 如个用空格分隔的整数每连续n个数代表一行,再往后n个代表下一行,以此类推。对应的值代表对应的网格是空矿位置,还是信号源,还是阻隔物,
第三行是ì、j,代表需要计算 array[i][j] 的网络信号值。注意:此处i和j均从 0开始,即第一行i为0;
例如:
bash
6 5
0 0 0 -1 0 0 0 0 0 0 0 0 -1 4 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0
1 4
输出
输出对应位置的网络信号值,如果网络信号未覆盖到,也输出0。
一个网格如果可以途径不同的传播衰减路径传达,取较大的值作为其信号值。
解题思路
把信号源向上下左右四个方向扩散,并把满足条件的扩散点作为新的信号源继续扩散,直到信号值为0、或者扩散到"坐标系"边缘
bash
6 5
0 0 0 -1 0 0 0 0 0 0 0 0 -1 4 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0
对于以上输入,得到的二维数组(可视为坐标系)为
bash
0 0 0 -1 0
0 0 0 0 0
0 0 -1 4 0
0 0 0 0 0
0 0 0 0 -1
0 0 0 0 0
扩散后,最终为
bash
0 0 1 -1 1
0 1 2 3 2
0 0 -1 4 3
0 1 2 3 2
0 0 1 2 -1
0 0 0 1 0
这里一定要注意,二维数组和我们上学时常用的xy轴坐标系还是有区别的,它们的原点不同,下面简化一下以上二维数组坐标系示意图
![](https://i-blog.csdnimg.cn/direct/102a13be7cbe49528cfa8eb03e8ce53d.jpeg)
bash
6 5
0 0 0 -1 0 0 0 0 0 0 0 0 -1 4 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0
1 4
这个输入,要求的输出array[1][4],它的结果是2;
我一开始把二维数组和上学时的xy轴坐标系给搞混了,死活想不明白(1,4)为啥是2,而不是1?
java代码
没有作输入的合法性校验,有兴趣的可以自己补充一下;
变量名起的也比较随意,大家不要学我
bash
import java.util.LinkedList;
import java.util.Scanner;
public class A60计算网络信号 {
private static LinkedList<Danyuange> list = new LinkedList<>();
private static int[][] zhouweiArr = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int m = sc.nextInt();
int n = sc.nextInt();
int[][] inputArr = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int d = sc.nextInt();
inputArr[i][j] = d;
if(d > 0) {
Danyuange yuan = new Danyuange();
yuan.setX(i);
yuan.setY(j);
yuan.setD(d);
list.add(yuan);
}
}
}
int queryX = sc.nextInt();
int queryY = sc.nextInt();
while (list.size() > 0) {
Danyuange danyuange = list.removeFirst();
kuosanMethod(inputArr, danyuange);
}
System.out.println(inputArr[queryX][queryY]);
}
private static void kuosanMethod(int[][] inputArr, Danyuange danyuange) {
int x = danyuange.getX();
int y = danyuange.getY();
int d = danyuange.getD();
for (int i = 0; i < 4; i++) {
int newX = x + zhouweiArr[i][0];
int newY = y + zhouweiArr[i][1];
if(newX >= 0 && newX < inputArr.length && newY >= 0 && newY < inputArr[0].length) {
if(inputArr[newX][newY] == 0) {
inputArr[newX][newY] = d - 1;
}
if(inputArr[newX][newY] < d && inputArr[newX][newY] >= 2 && inputArr[newX][newY] != -1) {
Danyuange newDanyuange = new Danyuange();
newDanyuange.setX(newX);
newDanyuange.setY(newY);
newDanyuange.setD(d-1);
list.add(newDanyuange);
}
}
}
}
private static class Danyuange {
int x;
int y;
int d;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getD() {
return d;
}
public void setD(int d) {
this.d = d;
}
}
}
61、简易内存池
题目
请实现一个简易内存池根据请求命令完成内存分配和释放内存池支持两种操作命令REQUEST和 RELEASE ;
其格式为:
REQUEST=请求的内存大小
表示请求分配指定大小内存
如果分配成功,返回分配到的内存首地址;
如果内存不足,或指定的大小为零则输出 error;
RELEASE=释放的内存首地址
表示释放掉之前分配的内存,释放成功无需输出如果,
释放不存在的首地址则输出 error
注意:
1.内存池总大小为 100 字节
2.内存池地址分配必须是连续内存,并优先从低地址分配
3.内存释放后可被再次分配,已释放的内存在空闲时不能被二次释放4.不会释放已申请的内存块的中间地址
5.释放操作只是针对首地址所对应的单个内存块进行操作,不会影响其他内存块
输入:
首行为整数 N,表示操作命令的个数取值范围 8<N<=100
接下来的N行,每行将给出一个操作命令;
操作命令和参数之间用"="分割
输出:
见题目输出要求
示例1:
bash
输入:
2
REQUEST=10
REQUEST=20
bash
输出:
0
10
示例2:
bash
输入:
6
REQUEST=10
REQUEST=20
RELEASE=0
RELEASE=20
REQUEST=20
REQUEST=10
bash
输出:
0
10
error
30
0
解题思路
1)用二维数组收录输入,会非常便于后续操作;当然也可以用单独的数组;
2)用treemap模拟内存(必须用treemap,需要key有序);
- RELEASE释放比较简单,包含key就remove,不包含就输出error;
- REQUEST单独一个方法处理,会使代码逻辑很清晰;自定义变量left初始值为0,表示与下一个已用内存首地址之间、未使用内存的首地址;
bash
0------------k1-v1------------k2-v2------------...------------kn-vn------------max
- 如上图示意,k-left就代表空闲内存的长度,k1-0就是最前边的空闲内存,从前往后、循环测试map的所有空闲内存key-left是否大于等于新内存l;
- ps:学会取map的key放入list的方法 List keyList = new ArrayList<>(map.keySet())
- 如果这个长度大于等于要存入的长度l,map直接put(left, left + l),并结束方法return;
- ps:还是为了方便,v不存真实的尾地址索引,而是直接存(索引+1),即占用内存长度是 [k, v)
- 如果这个长度小于要存入的长度l,则left = v,继续下一个循环;
- 当map的所有key都测试过,仍未找到可以放新内存l的地方,测试 max-left(此时left等于vn)是否大于等于l,
- 如果大于等于,put(left, left + l)
- 如果小于,输出error;
java代码
bash
public class A61简易内存池 {
private static Map<Integer, Integer> map = new TreeMap<>();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int orderNum = Integer.parseInt(sc.nextLine());
String[][] orders = new String[orderNum][];
for (int i = 0; i < orderNum; i++) {
orders[i] = sc.nextLine().split("=");
}
for (int j = 0; j < orderNum; j++) {
String order = orders[j][0];
int length = Integer.parseInt(orders[j][1]);
if("REQUEST".equals(order)) {
requestMethod(length);
} else {
if(map.containsKey(length)) {
map.remove(length);
} else {
System.out.println("error");
}
}
}
}
private static void requestMethod(int length) {
int left = 0;
if(map.size() == 0){
map.put(length, left + length);//包含左、不包含右
}
List<Integer> keyList = new ArrayList<>(map.keySet());
for (Integer key : keyList) {
if(key - left >= length) {
map.put(left, left + length);//包含左、不包含右
System.out.println(left);
return;
} else {
left = map.get(key);
}
}
//循环结束,表示所有kv之间,都没有找到能放length的地方;检查剩余字节
if(100 - left >= length) {
map.put(left, left + length);//包含左、不包含右
System.out.println(left);
} else {
System.out.println("error");
}
}
}