西山居校招笔试编程题

moye Lv6

题 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.util.Scanner;

public class Fibonacci {
// 方法:计算斐波那契数列的第n项
public static int fibonacci(int n) {
if (n == 0) {
return 0;
} else if (n == 1) {
return 1;
}

// 从2开始,利用两个变量存储前两项
int a = 0, b = 1, result = 0;
for (int i = 2; i <= n; i++) {
result = a + b;
a = b;
b = result;
}
return result;
}

public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入n: ");
int n = scanner.nextInt();
System.out.println("斐波那契数列的第" + n + "项是: " + fibonacci(n));
scanner.close();
}
}

题 2

题目描述

现有一个由 0(海洋)、1(陆地)、2(有敌军的陆地)构成的二维网格,请计算没有敌军驻扎的岛屿数量。岛屿总是被水包围,每座岛屿只能由水平方向或垂直方向上相邻的陆地连接而成。二维网格的四条边均被水包围。

函数定义:

  • 输入:一个二维数组 grid,表示地图。
  • 输出:返回没有敌军驻扎的岛屿数量。

规则:

  • 数组中的 0 代表海洋,1 代表没有敌军的陆地,2 代表有敌军的陆地。
  • 只能统计没有敌军的岛屿,数值为 1 的连续区域构成的岛屿。
  • 数组没有覆盖到的地方认为是海水。

示例

示例 1:

输入:

1
2
3
4
5
6
[
[1, 1, 1, 0],
[1, 0, 1, 0],
[0, 1, 0, 1],
[0, 1, 0, 0]
]

输出:`3```

解释:输入二维数组,计算出没有敌军岛屿数量,数组没有覆盖到的地方认为是海水。

示例 2:

输入:

1
2
3
4
5
6
[
[0, 1, 1, 0],
[2, 1, 1, 0],
[1, 0, 0, 1],
[0, 1, 1, 1]
]

输出:`1```

解释:计算二维数组中没有敌军的岛屿数量,敌军驻扎的地方(值为 2)不能计入岛屿。

思路分析

  • 可以使用 深度优先搜索(DFS)广度优先搜索(BFS) 来查找岛屿的数量。
  • 每当遇到 1 时,启动 DFS 或 BFS,递归遍历所有与之相邻的 1,并标记为已经访问过,统计岛屿的个数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public class IslandCounter {
private boolean[][] visited;
private int rows;
private int cols;
private int count = 0;
private boolean enemyFound;

public int countIslands(int[][] grid) {
if (grid == null || grid.length == 0) return 0;

rows = grid.length;
cols = grid[0].length;
visited = new boolean[rows][cols];

for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++)
if (!visited[i][j] && grid[i][j] != 0) {
enemyFound = false;
dfs(grid, i, j);
if (!enemyFound) {
count++;
}
}
}
return count;
}

private void dfs(int[][] grid, int i, int j) {
// 边界条件
if (i < 0 || i >= rows || j < 0 || j >= cols) return;
if (visited[i][j] || grid[i][j] == 0) return;

// 标记为已访问
visited[i][j] = true;

// 检查是否有敌军
if (grid[i][j] == 2) {
enemyFound = true;
}

// 递归访问相邻单元格
dfs(grid, i + 1, j);
dfs(grid, i - 1, j);
dfs(grid, i, j + 1);
dfs(grid, i, j - 1);
}

// 测试函数,可以使用示例输入来测试
public static void main(String[] args) {
IslandCounter ic = new IslandCounter();

int[][] grid1 = {
{1, 1, 1, 0},
{1, 0, 1, 0},
{0, 1, 0, 1},
{0, 1, 0, 0}
};
System.out.println(ic.countIslands(grid1)); // 输出:3

// 重置计数器和访问数组以供下一次测试
ic = new IslandCounter();
int[][] grid2 = {
{0, 1, 1, 0},
{2, 1, 1, 0},
{1, 0, 0, 1},
{0, 1, 1, 1}
};
System.out.println(ic.countIslands(grid2)); // 输出:1
}
}

题 3

题目描述

实现一个简单的网络协议编解码器,从标准输入中得到模拟的网络字节流,对其进行解码并输出解析后的内容。协议规范如下:

  • 字节流前两字节为常量,我们设置为 “SS”。
  • 接下来的 2 个字节为协议的长度(unsigned short)。
  • 接着是 2 个字节为协议号(unsigned short)。
  • 最后为消息体的长度。为了便于输出,这里我们使用的是不带结束符的字符串表示消息体。

例子:

如图所示:

  • 字节流的前两个字节为常量,我们设置为“SS”。
  • 接下来的 2 个字节为协议的长度(unsigned short)。
  • 接着是 2 个字节为协议号(unsigned short)。
  • 最后为消息体的长度。为了便于输出,我们这里使用的是不带结束符的字符串表示消息体。

示例

输入示例:

16 进制表示的字节流,16 进制的字母使用小写表示,如:

1
53530e00420048656c6c6f2053656153756e

输出示例:

解码后的消息体内容,输出协议号和消息体,协议号和消息体用空格隔开,如上所示的例子输出为:

1
66 Hello SeaSun

解析:

  • 输入字节流:53530e00420048656c6c6f2053656153756e
    • 前 2 字节:5353(常量 “SS”)
    • 长度:0e00(协议总长度 14)
    • 协议号:4200(协议号为 66)
    • 消息体:Hello SeaSun

示例

输入示例:

16 进制表示的字节流,16 进制的字母使用小写表示,如:

1
53530e00420048656c6c6f2053656153756e53531300580057656c636f6d6520746f205a6875486169

输出示例:

解码后的消息体内容,输出协议号和消息体,协议号和消息体用空格隔开,如上所示的例子输出为:

1
2
66 Hello SeaSun
88 Welcome to ZhuHai

示例

输入示例:

16 进制表示的字节流,16 进制的字母使用小写表示,如:

1
53530e00420048656c6c6f2053656153756e53531300580057656c636f6d6520746f205a687548616953530b007b00476f6f64206c75636b53530f00

输出示例:

解码后的消息体内容,输出协议号和消息体,协议号和消息体用空格隔开,如上所示的例子输出为:

1
2
3
66 Hello SeaSun
88 Welcome to ZhuHai
123 Good luck
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.util.*;

public class Mainxs3 {
public static void main(String[] args) {
// 读取输入的十六进制字符串
Scanner scanner = new Scanner(System.in);
String hexString = scanner.nextLine();
// 将十六进制字符串转换为字节数组
byte[] bytes = hexStringToByteArray(hexString);

int index = 0;
while (index + 5 < bytes.length) { // 至少需要 6 个字节才能解析一个包
// 检查前两个字节是否为常量 "SS"
if (bytes[index] != 0x53 || bytes[index + 1] != 0x53) {
// 非法包,跳过或结束
break;
}
index += 2;
// 读取长度字段(2 字节,little-endian)
if (index + 1 >= bytes.length) break; // 防止越界
int length = (bytes[index] & 0xFF) | ((bytes[index + 1] & 0xFF) << 8);
index += 2;
// 检查剩余数据是否足够
if (index + length > bytes.length) break;
// 读取协议号(2 字节,little-endian)
int protocolNumber = (bytes[index] & 0xFF) | ((bytes[index + 1] & 0xFF) << 8);
index += 2;
// 计算消息体长度
int messageLength = length - 2; // 减去协议号占用的 2 字节
// 读取消息体
byte[] messageBytes = Arrays.copyOfRange(bytes, index, index + messageLength);
index += messageLength;
// 将消息体转换为字符串
String message = new String(messageBytes);
// 输出协议号和消息体
System.out.println(protocolNumber + " " + message);
}
}

// 将十六进制字符串转换为字节数组的辅助方法
private static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
// 每两个十六进制字符转换为一个字节
for (int i = 0; i < len; i += 2) {
// 将十六进制字符转换为字节
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
}

  • 标题: 西山居校招笔试编程题
  • 作者: moye
  • 创建于 : 2024-10-13 11:46:13
  • 更新于 : 2025-12-11 14:39:48
  • 链接: https://www.kanes.top/2024/10/13/西山居校招笔试编程题/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论