题目描述
模拟一套简化的序列化传输方式,请实现下面的数据编码与解码过程
1.编码前数据格式为 [位置,类型,值],多个数据的时候用逗号分隔,位置仅支持数字,不考虑重复等场景;类型仅支持:Integer / String / Compose(Compose的数据类型表示该存储的数据也需要编码)
2.编码后数据参考图示,数据区的格式是:位置#类型#长度#数据,类型存储需要编码,Integer->0;String->1;Compose->2,长度是指数据的字符长度;数据仅允许数字、大小写字母、空格。
3.输入的编码字符长度不能超过1000,一个数据的格式错误,则解析剩下数据,其他错误输出ENCODE_ERROR。
4.输入的解码字符不能超过1000,数据区异常则跳过继续解析剩余数据区,其他异常输出DECODE_ERROR。
输入描述
输入有两行:
第一行是命令,1表示编码,2表示解码
第二行输入待编码、解码的字符
数据最多嵌套10层,[1,Compose,[1,String,Second]] 为2层嵌套。
输出描述
如果输入要求是编码,则输出编码结果;
如果输入要求是解码,则输出解码结果;
当异常时输出对应的错误字符。
为了实现数据的编码与解码功能,我们需要设计两个主要功能:编码和解码。以下是如何实现这些功能的详细步骤及Java代码示例。
编码说明
-
输入格式:
[位置,类型,值]
,其中位置
是一个数字,类型
可以是Integer
,String
或Compose
,值
对应不同的类型
,如果类型
是Compose
,值
本身也是一个[位置,类型,值]
的列表。
-
编码规则:
- 对于
Integer
类型,编码格式为位置#0#长度#数据
。 - 对于
String
类型,编码格式为位置#1#长度#数据
。 - 对于
Compose
类型,编码格式为位置#2#长度#数据
,其中数据
是嵌套的编码结果。
- 对于
解码说明
-
输入格式:
- 数据区的格式为
位置#类型#长度#数据
。
- 数据区的格式为
-
解码规则:
- 根据
类型
字段解析数据,并重建原始格式。 - 处理嵌套数据时,需要解析内部的编码格式。
- 根据
Java 实现
下面是实现编码和解码的 Java 代码示例:
import java.util.*;
public class DataCodec {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int command = scanner.nextInt();
scanner.nextLine(); // Consume newline
String input = scanner.nextLine();
if (command == 1) {
// Encode
try {
String encoded = encode(input);
System.out.println(encoded);
} catch (Exception e) {
System.out.println("ENCODE_ERROR");
}
} else if (command == 2) {
// Decode
try {
String decoded = decode(input);
System.out.println(decoded);
} catch (Exception e) {
System.out.println("DECODE_ERROR");
}
}
}
// Encode method
public static String encode(String data) throws Exception {
// Parse input data
List<String> result = new ArrayList<>();
String[] parts = data.substring(1, data.length() - 1).split(",(?=\\d)"); // Split by comma not in quotes
for (String part : parts) {
String[] elements = part.split(",");
if (elements.length != 3) {
throw new Exception("Encoding Error");
}
String position = elements[0].trim();
String type = elements[1].trim();
String value = elements[2].trim();
switch (type) {
case "Integer":
result.add(encodeInteger(position, value));
break;
case "String":
result.add(encodeString(position, value));
break;
case "Compose":
result.add(encodeCompose(position, value));
break;
default:
throw new Exception("Encoding Error");
}
}
return String.join(";", result);
}
private static String encodeInteger(String position, String value) {
return position + "#0#" + value.length() + "#" + value;
}
private static String encodeString(String position, String value) {
return position + "#1#" + value.length() + "#" + value;
}
private static String encodeCompose(String position, String value) throws Exception {
// Recursively encode Compose type
String[] subData = value.substring(1, value.length() - 1).split(",");
StringBuilder encoded = new StringBuilder();
for (String sub : subData) {
String[] elements = sub.split(",");
String subPosition = elements[0].trim();
String subType = elements[1].trim();
String subValue = elements[2].trim();
switch (subType) {
case "Integer":
encoded.append(encodeInteger(subPosition, subValue));
break;
case "String":
encoded.append(encodeString(subPosition, subValue));
break;
case "Compose":
encoded.append(encodeCompose(subPosition, subValue));
break;
default:
throw new Exception("Encoding Error");
}
encoded.append(";");
}
return position + "#2#" + encoded.length() + "#" + encoded.toString();
}
// Decode method
public static String decode(String data) throws Exception {
String[] parts = data.split(";");
List<String> result = new ArrayList<>();
for (String part : parts) {
String[] elements = part.split("#");
if (elements.length != 4) {
throw new Exception("Decoding Error");
}
String position = elements[0];
String type = elements[1];
int length = Integer.parseInt(elements[2]);
String value = elements[3];
switch (type) {
case "0":
result.add(decodeInteger(position, value));
break;
case "1":
result.add(decodeString(position, value));
break;
case "2":
result.add(decodeCompose(position, value));
break;
default:
throw new Exception("Decoding Error");
}
}
return result.toString();
}
private static String decodeInteger(String position, String value) {
return "[" + position + ", Integer, " + value + "]";
}
private static String decodeString(String position, String value) {
return "[" + position + ", String, " + value + "]";
}
private static String decodeCompose(String position, String value) throws Exception {
StringBuilder decoded = new StringBuilder();
String[] subParts = value.split(";");
decoded.append("[").append(position).append(", Compose, [");
for (int i = 0; i < subParts.length; i++) {
String[] elements = subParts[i].split("#");
String subPosition = elements[0];
String subType = elements[1];
int length = Integer.parseInt(elements[2]);
String subValue = elements[3];
switch (subType) {
case "0":
decoded.append("[").append(subPosition).append(", Integer, ").append(subValue).append("]");
break;
case "1":
decoded.append("[").append(subPosition).append(", String, ").append(subValue).append("]");
break;
case "2":
decoded.append(decodeCompose(subPosition, subValue));
break;
default:
throw new Exception("Decoding Error");
}
if (i < subParts.length - 1) {
decoded.append(", ");
}
}
decoded.append("]]");
return decoded.toString();
}
}
代码解释
-
编码函数:
- 将输入的格式解析为
位置#类型#长度#数据
的形式。 - 对于
Compose
类型,递归编码内部的结构。
- 将输入的格式解析为
-
解码函数:
- 解析编码后的数据区,根据
类型
还原原始格式。 - 处理嵌套的
Compose
类型,递归解码。
- 解析编码后的数据区,根据
-
错误处理:
- 编码和解码过程中的格式错误都被捕获并标记为
ENCODE_ERROR
或DECODE_ERROR
。
- 编码和解码过程中的格式错误都被捕获并标记为
这样可以确保数据的正确编码和解码,且处理了各种边界情况和错误。
refer: https://www.nowcoder.com/discuss/637256237398147072?sourceSSR=dynamic
题目
现需要在某城市进行5G网络建设,已经选取N个地点设置5G基站,编号固定为1到N,接
下来需要各个基站之间使用光纤进行连接以确保基站能互联互通,不同基站之间架设光纤的成
本各不相同,且有些节点之间已经存在光纤相连,请你设计算法,计算出能联通这些基站的最
小成本是多少。
注意,基站的联通具有传递性,即基站A与基站B架设了光纤,基站B与基站C也架设了光
纤,则基站A与基站C视为可以互相联通
输入描述
第一行输入表示基站的个数N,其中0<N<=20
第二行输入表示具备光纤直连条件的基站对的数目M,其中0 < M < N * (N - 1) / 2
第三行开始连续输入M行数据,格式为X Y Z P ,其中X Y表示基站的编号,0 < X < = ?,0
< Y < = N且X不等于丫,Z表示在X Y之间架设光纤的成本,其中0 < Z < 1 0 0 , P表示是否
已存在光纤连接,0表示未连接,1表示已连接。
输出描述
如果给定条件,可以建设成功互联互通的5G网络,则输出最小的建设成本,
如果给定条件,无法建设成功互联互通的5G网络,则输出-1
示例1:
输入
3
3
1 2 3 0
1 3 1 0
2 3 5 0
输出
4
说明
只需要在1,2以及2,3基站之间铺设光纤,其成本为3+1=4
示例2
输入
3
1
1 2 5 0
输出
-1
说明
3基站无法与其他基站连接,输出-1
示例3:
输入
3
3
1 2 3 0
1 3 1 0
2 3 5 1
输出
1
说明
2,3基站已有光纤相连,只有要再1,3站点2向铺设,其成本为1
这个问题是一个典型的 最小生成树 (MST) 问题。我们需要在一个图中找到最小的连接所有节点的边的总成本。这个问题可以通过 Kruskal's 算法 或 Prim's 算法 来解决。
问题分析
-
输入:
- N: 基站的数量。
- M: 可能存在光纤的连接对的数量。
- 接下来M行包含:
X Y Z P
:X
和Y
是基站编号。Z
是架设光纤的成本。P
表示是否已存在光纤连接(1表示已连接,0表示未连接)。
-
目标:
- 找到最小的建设成本使所有基站互联。
- 如果无法实现互联,则输出 -1。
解决方案
-
构建图:
- 将所有光纤连接(包括已存在的和需要建设的)转换成边的形式
(成本, 起点, 终点)
。 - 已存在的光纤连接(
P = 1
)的成本为 0。
- 将所有光纤连接(包括已存在的和需要建设的)转换成边的形式
-
应用 Kruskal's 算法:
- 排序: 按边的成本排序。
- 并查集: 用于检测环路并合并不同的集合。
- 选边: 逐步选择成本最小的边,确保选取的边不会形成环路,直到所有基站都被连接。
-
判断:
- 如果在构建最小生成树的过程中,不能连接所有基站,则返回 -1。
Java 实现
以下是 Java 代码示例,使用 Kruskal's 算法来解决最小生成树问题:
import java.util.*;
public class MinimumSpanningTree {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt(); // Number of base stations
int M = scanner.nextInt(); // Number of possible fiber connections
List<Edge> edges = new ArrayList<>();
// Reading the edges
for (int i = 0; i < M; i++) {
int X = scanner.nextInt();
int Y = scanner.nextInt();
int Z = scanner.nextInt();
int P = scanner.nextInt();
if (P == 1) {
Z = 0; // If fiber is already connected, cost is zero
}
edges.add(new Edge(Z, X - 1, Y - 1)); // Convert to zero-based index
}
// Apply Kruskal's algorithm
int result = kruskal(N, edges);
System.out.println(result);
}
// Edge class
static class Edge {
int cost;
int u, v;
Edge(int cost, int u, int v) {
this.cost = cost;
this.u = u;
this.v = v;
}
}
// Kruskal's algorithm
public static int kruskal(int N, List<Edge> edges) {
// Sort edges by cost
Collections.sort(edges, Comparator.comparingInt(e -> e.cost));
// Union-Find data structure
int[] parent = new int[N];
int[] rank = new int[N];
for (int i = 0; i < N; i++) {
parent[i] = i;
rank[i] = 0;
}
// Helper methods for Union-Find
int find(int i) {
if (parent[i] != i) {
parent[i] = find(parent[i]);
}
return parent[i];
}
void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
if (rank[rootX] > rank[rootY]) {
parent[rootY] = rootX;
} else if (rank[rootX] < rank[rootY]) {
parent[rootX] = rootY;
} else {
parent[rootY] = rootX;
rank[rootX]++;
}
}
}
int minCost = 0;
int edgesUsed = 0;
for (Edge edge : edges) {
int rootU = find(edge.u);
int rootV = find(edge.v);
if (rootU != rootV) {
union(rootU, rootV);
minCost += edge.cost;
edgesUsed++;
}
}
// Check if we used exactly N-1 edges (tree with N nodes)
if (edgesUsed == N - 1) {
return minCost;
} else {
return -1; // Not all nodes are connected
}
}
}
代码解释
-
输入处理:
- 读取输入数据并构造
Edge
对象。 - 对于已存在的光纤连接,将其成本设置为 0。
- 读取输入数据并构造
-
Kruskal's 算法:
- 排序边按照成本。
- 使用并查集(Union-Find)结构来管理连通性。
- 遍历边,选择未形成环路的边来加入最小生成树。
-
结果判断:
- 如果成功连接所有基站,则返回总成本;否则返回 -1。
题目描述
一个歌手准备从A城去B城参加演出
按照合同,他必须在T天内赶到
歌手不能往回走
每两座城市之间需要的天数都可以提前获知。
歌手在每座城市都可以在路边卖唱赚钱。经过调研,歌手提前获知了每座城市卖唱的收入预期: 如果在一座城市第一天卖唱可以赚M,后续每天的收入会减少D(第二天赚的钱是M -D,第三天是M-2D…)如果收入减到0就不会再少了。
歌手到达后的第二天才能开始卖唱。如果今天卖过唱,第二天才能出发
贪心的歌手最多可以赚多少钱?
输入描述
第一行两个数字 T 和 N,中间用空格隔开
T代表总天数;
N代表路上经过N座城市;
0 < T < 1000,0 < N < 100
第二行N+1个数字,中间用空格隔开
代表每两座城市之间耗费的时间。
其总和<=T。
接下来N行,每行两个数字M和D,中间用空格隔开.
代表每个城市的收入预期。
0<M < 1000,0<D <100
输出描述
一个数字。代表歌手最多
要解决这个问题,我们需要设计一个动态规划算法来最大化歌手在规定天数内的总收入。我们将采用动态规划来解决这个问题,因为我们需要考虑不同城市之间的旅行时间以及在城市中卖唱的收益随时间的变化。
动态规划思路
-
定义状态:
dp[i][t]
表示在第i
座城市并且已经用t
天的情况下,能获得的最大收入。
-
状态转移:
-
从城市
j
移动到城市i
的时间为time[j][i]
。我们可以在城市j
待k
天后再出发。 -
在城市
j
待k
天的收入是:M_j - k * D_j
,如果收入低于 0,则为 0。 -
所以
dp[i][t]
可以通过考虑从所有其他城市j
转移过来得到:[
dp[i][t] = \max_{j}(dp[j][t - time[j][i] - k] + \text{income})
]
其中,income
是在城市j
待k
天获得的收入。
-
-
初始化:
dp[i][t]
需要初始化为非常小的值(负无穷),因为我们要找的是最大值。- 在城市
i
到达时的初始收入是 0,因为没有时间在城市中待过。
-
边界条件:
- 从任何城市到达城市
i
,必须满足剩余时间t - time[j][i] - k >= 0
。 - 遍历所有可能的
k
(即在城市j
中待的天数)来计算最大收入。
- 从任何城市到达城市
Java 实现
以下是一个基于动态规划的 Java 实现代码:
import java.util.Scanner;
public class MaximumEarnings {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Read input values
int T = scanner.nextInt();
int N = scanner.nextInt();
int[] travelTime = new int[N + 1];
for (int i = 0; i <= N; i++) {
travelTime[i] = scanner.nextInt();
}
int[][] incomeData = new int[N][2]; // incomeData[i][0] = M, incomeData[i][1] = D
for (int i = 0; i < N; i++) {
incomeData[i][0] = scanner.nextInt();
incomeData[i][1] = scanner.nextInt();
}
// Initialize DP table
int[][] dp = new int[N + 1][T + 1];
for (int i = 0; i <= N; i++) {
for (int j = 0; j <= T; j++) {
dp[i][j] = Integer.MIN_VALUE;
}
}
// Starting point
dp[0][0] = 0;
// Compute DP table
for (int t = 0; t <= T; t++) {
for (int i = 0; i < N; i++) {
if (dp[i][t] != Integer.MIN_VALUE) {
for (int j = 0; j < N; j++) {
if (i != j) {
int timeToTravel = travelTime[i + 1] + travelTime[j + 1];
if (t + timeToTravel <= T) {
for (int k = 0; k <= T - timeToTravel; k++) {
int income = incomeData[j][0] - k * incomeData[j][1];
if (income < 0) {
income = 0;
}
dp[j + 1][t + timeToTravel] = Math.max(dp[j + 1][t + timeToTravel], dp[i][t] + income);
}
}
}
}
}
}
}
// Get the result
int maxEarnings = 0;
for (int i = 0; i <= T; i++) {
maxEarnings = Math.max(maxEarnings, dp[N][i]);
}
System.out.println(maxEarnings);
}
}
代码解释
-
输入处理:
- 读取天数
T
和城市数量N
。 - 读取每两座城市之间的旅行时间和每个城市的卖唱预期数据。
- 读取天数
-
动态规划表初始化:
dp[i][t]
表示到达城市i
并且已经用t
天的情况下的最大收入。
-
动态规划计算:
- 遍历每座城市的每一天,更新
dp
表格。
- 遍历每座城市的每一天,更新
-
结果输出:
- 输出在所有时间中获得的最大收入。
注意事项
- 确保考虑所有可能的天数
k
,即在城市中待的天数。 - 确保边界条件和转换条件正确处理,避免数组越界和计算错误。
【信道分配】
算法工程师小明面对着这样一个问题 ,需要将通信用的信道分配给尽量多的用户:
信道的条件及分配规则如下:
1)所有信道都有属性:”阶”。阶为 r的信道的容量为 2^r比特;
2)所有用户需要传输的数据量都一样:D比特;
3)一个用户可以分配多个信道,但每个信道只能分配给一 个用户;
4)只有当分配给一个用户的所有信道的容量和>=D,用户才能传输数据;
给出一组信道资源,最多可以为多少用户传输数据?
输入描述:
第一行,一个数字 R。R为最大阶数。0<=R<20
第二行,R+1个数字,用空格隔开。
代表每种信道的数量 Ni。按照阶的值从小到大排列。
0<=i<=R,0<=Ni<1000.
第三行,一个数字 D。
D为单个用户需要传输的数据量。0<D<1000000
输出描述:
一个数字 ,代表最多可以供多少用户传输数据。
示例 1:
输入
5
10 5 0 1 3 2
30
输出
4
要解决这个信道分配问题,我们可以将其视作一个背包问题。问题的目标是尽可能多地为用户分配信道,使得每个用户的信道总容量达到或超过所需的数据量 D
。下面是一个详细的算法步骤和实现。
算法步骤
-
数据表示:
- 记录每种阶数的信道数量。
- 计算每种阶数信道的容量。
- 将所有信道的容量存储在一个列表中,方便后续处理。
-
背包问题转化:
- 每个用户的需求可以视作一个背包问题,其中每个信道的容量是背包中物品的重量。
- 目标是找到最小的背包组合,使其总容量不小于
D
。
-
动态规划:
- 使用动态规划来解决变体背包问题,计算达到或超过
D
的最小信道组合。 - 通过一个布尔数组
dp
来记录是否可以用i
个信道的组合满足需求D
。
- 使用动态规划来解决变体背包问题,计算达到或超过
-
计算最大用户数:
- 根据可用信道的数量和每个用户所需信道的数量,计算最多可以服务的用户数。
动态规划实现
以下是完整的 Java 代码实现:
import java.util.Scanner;
import java.util.Arrays;
public class ChannelAllocation {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Read input values
int R = scanner.nextInt();
int[] channels = new int[R + 1];
for (int i = 0; i <= R; i++) {
channels[i] = scanner.nextInt();
}
int D = scanner.nextInt();
// Calculate the capacity of each channel type
int[] capacities = new int[R + 1];
for (int i = 0; i <= R; i++) {
capacities[i] = (int) Math.pow(2, i);
}
// Create a list of all channel capacities with their counts
int[] channelList = new int[1000 * (R + 1)];
int index = 0;
for (int i = 0; i <= R; i++) {
for (int j = 0; j < channels[i]; j++) {
channelList[index++] = capacities[i];
}
}
// Dynamic programming to find the minimum channels required to achieve at least D capacity
int[] dp = new int[D + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0; // No channels needed to achieve 0 capacity
for (int capacity : channelList) {
for (int j = D; j >= capacity; j--) {
if (dp[j - capacity] != Integer.MAX_VALUE) {
dp[j] = Math.min(dp[j], dp[j - capacity] + 1);
}
}
}
// Find the minimum channels needed to meet the capacity
int minChannels = dp[D];
if (minChannels == Integer.MAX_VALUE) {
minChannels = 0;
}
// Calculate the maximum number of users that can be supported
int maxUsers = 0;
if (minChannels > 0) {
int totalChannels = Arrays.stream(channelList).sum();
maxUsers = totalChannels / minChannels;
}
System.out.println(maxUsers);
}
}
代码解释
-
输入处理:
- 读取最大阶数
R
和每种阶数的信道数量。 - 计算每种信道的容量(
2^r
),并将所有信道的容量存储在channelList
中。
- 读取最大阶数
-
动态规划:
- 初始化
dp
数组,dp[i]
表示用最少的信道数达到i
比特的容量。 - 遍历所有信道容量,更新
dp
数组来计算达到至少D
比特所需的最小信道数。
- 初始化
-
计算结果:
- 找到达到
D
比特所需的最小信道数。 - 使用可用信道的总数除以最小所需信道数,计算最大用户数。
- 找到达到
注意事项
- 确保所有数据处理和计算在合法范围内,防止数组越界和溢出。
- 动态规划需要处理的状态和转移逻辑需要准确,以保证正确计算所需的信道数量。
题目描述
推荐多样性需要从多个列表中选择元素,一次性要返回N屏数据(窗口数量),每屏展示K个元素(窗口大小),选择策略 1.各个列表元素需要做穿插处理,即先从第一个列表中为每屏选择一元素,再从第二个列表中为每屏选择一个元素,依次类推 2.每个列表的元素尽量均分为N份,如果不够N个,也要全部分配完,比如下面的例子: (1)从第一个列表中选择4条0 12 3,分别放到4个窗口中 (2)从第二个列表中选择4条10 11 12 13,分别放到4个窗口中 (3)从第三个列表中选择4条20 21 22 23,分别放到4个窗口 (4)再从第一个列表中选择4条4 5 6 7,分别放到4个窗口中 (5)再从第一个列表中选择,由于数量不足4条,取剩下的2条,放到窗1和窗口2(6)再从第二个列表中选择,由于数量不足4条并且总的元素数达到窗口要求,取18 19放到窗口3和窗口4
输入
第一行输入为N,表示需要输出的窗口数量,取值范围[1,10] 第二行输入为K,表示每个窗口需要的元素数量Q,取值范用[1,100]之后的行数不定(行数取值范围[1,10],表示每个列表输出的元素列表。元素之间以空格分隔,已经过准序外理,每人列表输出的元素数量取值范围[1,100]
输出
输出元素列表,元素数量=窗口数量“窗口大小,元素之间以空格分隔,多个窗口合并为一个列表输出,参考样例:先输出窗口1的元素列表,再输出窗口2的元素列表,再输出窗口3的元素列表,最后输出窗口4的元素列表
样例输入
4
7
0 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
样例输出
0 10 20 4 14 24 8 1 11 21 5 15 25 9 2 12 22 6 16 26 18 3 13 23 7 17 27 19
这个问题可以通过模拟按要求从多个列表中选择元素来完成。为了实现题目描述中的需求,我们需要遵循以下步骤:
-
解析输入:
- 读取窗口数量
N
和每个窗口的大小K
。 - 读取每个列表的元素,直到所有列表读取完毕。
- 读取窗口数量
-
均分处理:
- 将每个列表的元素尽量均分为
N
份。如果某个列表的元素数量不足N
,那么剩余的元素需要根据实际情况填充到窗口中。
- 将每个列表的元素尽量均分为
-
按顺序选择元素:
- 按照顺序,从每个列表中选出元素填充到每个窗口中,确保每个窗口的元素来自于不同的列表。
-
生成输出:
- 将每个窗口的元素按照顺序拼接成输出格式。
实现步骤
-
读取和解析输入:
- 首先读取
N
和K
,然后读取各个列表的元素。
- 首先读取
-
分配列表元素:
- 将每个列表的元素分配到窗口中。如果某个列表的元素数量不足
N
,需要将其余的元素根据实际情况分配到窗口中。
- 将每个列表的元素分配到窗口中。如果某个列表的元素数量不足
-
输出结果:
- 将每个窗口的元素按照顺序输出。
以下是实现代码:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;
public class ChannelAllocation {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Read N and K
int N = scanner.nextInt();
int K = scanner.nextInt();
// Read all lists
List<List<Integer>> lists = new ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
if (line.isEmpty()) {
break;
}
String[] parts = line.split("\\s+");
List<Integer> list = new ArrayList<>();
for (String part : parts) {
list.add(Integer.parseInt(part));
}
lists.add(list);
}
// Initialize result list
List<List<Integer>> result = new ArrayList<>();
for (int i = 0; i < N; i++) {
result.add(new ArrayList<>());
}
// Process each list
for (List<Integer> list : lists) {
int size = list.size();
int itemsPerWindow = (int) Math.ceil((double) size / N);
int currentIndex = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < K; j++) {
if (currentIndex < size) {
result.get(i).add(list.get(currentIndex++));
} else {
break;
}
}
if (currentIndex >= size) {
break;
}
}
}
// Print results
for (List<Integer> window : result) {
for (int i = 0; i < K; i++) {
if (i < window.size()) {
System.out.print(window.get(i) + " ");
}
}
}
}
}
代码解释
-
输入读取:
- 从标准输入中读取
N
和K
,然后读取多个列表的数据。
- 从标准输入中读取
-
处理列表:
- 对每个列表中的元素按窗口的顺序进行分配。由于需要处理均分的情况,因此每个列表的元素被均匀地分配到窗口中。
-
生成输出:
- 按要求将每个窗口的元素输出到标准输出中。
注意事项
- 确保正确处理列表的边界情况,例如列表长度不足
N
的情况。 - 确保输出格式符合要求,尤其是每个窗口元素的顺序。
这个解决方案通过模拟分配过程,确保了按照要求将元素分配到每个窗口中,并且考虑了多种情况。
题目描述
- 老李是货运公司承运人,老李的货车额定载货重量为
wt
。 - 现有两种货物,货物A单件重量为
wa
,单件运费利润为pa
,货物B单件重量为wb
,单件运费利润为pb
。 - 老李每次发车时载货总重量刚好为货车额定载货重量
wt
,车上必须同时有货物A和货物B,货物A、B不可切割。 - 老李单车次满载运输可获得的最高利润是多少?
输入描述:
- 第一列输入为货物A的单件重量
wa
,0 < wa < 10000
。 - 第二列输入为货物B的单件重量
wb
,0 < wb < 10000
。 - 第三列输入为货车的额定载重
wt
,0 < wt < 100000
。 - 第四列输入为货物A的单件运费利润
pa
,0 < pa < 1000
。 - 第五列输入为货物B的单件运费利润
pb
,0 < pb < 1000
。
输出描述:
- 单次满载运输的最高利润。
示例1:
输入:
10 8 36 15 7
输出:
44
说明:
货车总重量为36,货物A的单件重量为10,单件利润为15;货物B的单件重量为8,单件利润为7。最佳方案是装载2件货物A和3件货物B,总重量为36,利润为 2 * 15 + 3 * 7 = 44
。
示例2:
输入:
1 1 2 1 1
输出:
2
说明:
货车总重量为2,货物A和货物B的重量和利润都为1,最佳方案是装载1件货物A和1件货物B,总重量为2,利润为 1 * 1 + 1 * 1 = 2
。
Java 解题代码
import java.util.Scanner;
public class MaximumProfit {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取输入数据
int wa = scanner.nextInt();
int wb = scanner.nextInt();
int wt = scanner.nextInt();
int pa = scanner.nextInt();
int pb = scanner.nextInt();
scanner.close();
// 最大利润的初始值为0
int maxProfit = 0;
// 遍历所有可能的货物A的数量
for (int countA = 1; wa * countA < wt; countA++) {
// 计算剩余的重量
int remainingWeight = wt - (wa * countA);
// 如果剩余的重量可以被货物B的重量整除,则计算利润
if (remainingWeight % wb == 0) {
int countB = remainingWeight / wb;
// 计算当前方案的利润
int currentProfit = (pa * countA) + (pb * countB);
// 更新最大利润
maxProfit = Math.max(maxProfit, currentProfit);
}
}
// 输出结果
System.out.println(maxProfit);
}
}
代码解释
-
读取输入:
- 使用
Scanner
读取五个输入值,分别代表货物A的单件重量、货物B的单件重量、货车的额定载重、货物A的单件运费利润、货物B的单件运费利润。
- 使用
-
计算最大利润:
- 遍历所有可能的货物A的数量
countA
。 - 对于每一种可能的
countA
,计算剩余重量remainingWeight
。 - 检查剩余重量是否能被货物B的重量整除。
- 计算当前方案的利润,并更新最大利润。
- 遍历所有可能的货物A的数量
-
输出结果:
- 打印最大利润。
题目描述
一根 X
米长的树木,伐木工切割成不同长度的木材后进行交易,交易价格为每根木头长度的乘积。规定切割后的每根木头长度都为正整数;也可以不切割,直接拿整根树木进行交易。
请问伐木工如何尽量少的切割,才能使收益最大化?
输入描述:
- 木材的长度(
X ≤ 50
)
输出描述:
- 输出最优收益时的各个树木长度,以空格分隔,按升序排列
用例
输入:
10
输出:
3 3 4
说明:
对于10米长的树木,伐木工可以通过切割成长度为 3, 3, 4
的木材,使收益最大化。这个结果的收益为 3 * 3 * 4 = 36
。
Java 解题代码
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Collections;
public class MaxProfitWoodcutting {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int X = scanner.nextInt();
scanner.close();
// DP数组,dp[i]表示长度为i的树木的最大收益
int[] dp = new int[X + 1];
// 存储每个长度对应的切割结果
ArrayList<ArrayList<Integer>> cuts = new ArrayList<>();
// 初始化
for (int i = 0; i <= X; i++) {
dp[i] = i; // 直接取整根木材的价值
cuts.add(new ArrayList<Integer>());
cuts.get(i).add(i);
}
// 计算每个长度的最大收益
for (int i = 1; i <= X; i++) {
for (int j = 1; j <= i / 2; j++) {
int product = dp[j] * dp[i - j];
if (product > dp[i]) {
dp[i] = product;
// 记录最佳切割方案
cuts.set(i, new ArrayList<>(cuts.get(j)));
cuts.get(i).addAll(cuts.get(i - j));
Collections.sort(cuts.get(i));
}
}
}
// 打印输出最优切割方案
for (int length : cuts.get(X)) {
System.out.print(length + " ");
}
}
}
代码解释
-
初始化:
- 使用
dp
数组来保存每个长度木材的最大收益。 - 使用
cuts
列表来保存每个长度木材对应的最佳切割方案。
- 使用
-
计算最大收益:
- 对于每种可能的长度
i
,尝试从1
到i / 2
的所有切割方案。 - 计算每种切割方案的收益,更新
dp[i]
和cuts[i]
。
- 对于每种可能的长度
-
输出结果:
- 从
cuts[X]
列表中读取最优的木材长度,按照升序排列输出。
- 从
这个算法采用了动态规划的思想,时间复杂度是 (O(X^2)),适合处理木材长度 X
最大为 50 的情况。
题目描述
将一个 CSV 格式的数据文件中包含有单元格引用的内容替换为对应单元格内容的实际值。
CSV(Comma Separated Values)格式的数据文件使用逗号 ,
作为分隔符将各单元的内容进行分隔。每个单元格的内容可能包含字母和数字,以及使用 < >
分隔的单元格引用,例如 <A>
表示引用第一个单元的值。
输入描述:
- 输入只有一行数据,用逗号分隔每个单元格,行尾没有逗号。
- 每个单元格的内容包含字母和数字,以及使用
< >
分隔的单元格引用,例如<A>
表示引用第一个单元的值。 - 每个单元格的内容,在替换前和替换后均不超过100个字符。
- 引用单元格的位置不受限制,允许排在后面的单元格被排在前面的单元格引用。
- 不存在循环引用的情况,例如:
A: aCd<B>8U
,B: KAy<A>uZq0
。 - 不存在多重
< >
的情况,一个单元只能引用一个其他单元格,例如:A: aCdOu
,B: kAydzco
,C: y<<A><B>>d
。
输出描述:
- 输出替换后的结果。如果有错误的单元格引用方式,则输出字符串
"-1"
表示错误。
用例
输入:
1,2<A>00
输出:
1,2100
说明:
第二个单元中有对 A
单元的引用,A
单元格的值为 1
,替换时,将 A
单元的内容替代 <A>
的位置,并与其他内容合并。
输入:
1<B>2,1
输出:
112,1
说明:
第一个单元中有对 B
单元的引用,B
单元格的值为 1
,替换时,将第二个单元的内容替代 <B>
的位置,并与其他内容合并。
输入:
<A>
输出:
-1
说明:
第一个单元中有错误的单元格引用方式,输出字符串 "-1"
表示错误。
Java 解题代码
import java.util.Scanner;
import java.util.HashMap;
import java.util.Map;
public class CellReferenceResolver {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
scanner.close();
String[] cells = input.split(",");
int n = cells.length;
Map<Integer, String> cellMap = new HashMap<>();
// Fill cellMap with cell values
for (int i = 0; i < n; i++) {
cellMap.put(i, cells[i]);
}
String[] resolvedCells = new String[n];
boolean[] visited = new boolean[n];
// Resolve each cell
for (int i = 0; i < n; i++) {
String resolved = resolveCell(i, cellMap, visited);
if (resolved.equals("-1")) {
System.out.println(resolved);
return;
}
resolvedCells[i] = resolved;
}
// Print the resolved cells
System.out.println(String.join(",", resolvedCells));
}
private static String resolveCell(int index, Map<Integer, String> cellMap, boolean[] visited) {
if (visited[index]) {
return "-1"; // Avoid cycles, though the problem states no cycles
}
visited[index] = true;
String cell = cellMap.get(index);
StringBuilder resolved = new StringBuilder();
int len = cell.length();
for (int i = 0; i < len; i++) {
if (cell.charAt(i) == '<') {
int j = i + 1;
while (j < len && cell.charAt(j) != '>') {
j++;
}
if (j >= len) {
return "-1"; // Error, unmatched '<'
}
String ref = cell.substring(i + 1, j);
int refIndex = ref.charAt(0) - 'A';
if (refIndex < 0 || refIndex >= cellMap.size()) {
return "-1"; // Error, out of bounds
}
String refValue = resolveCell(refIndex, cellMap, visited);
if (refValue.equals("-1")) {
return "-1";
}
resolved.append(refValue);
i = j;
} else {
resolved.append(cell.charAt(i));
}
}
visited[index] = false;
return resolved.toString();
}
}
代码解释
-
读取输入:
- 使用
Scanner
从标准输入读取单行数据,并将其按逗号分隔成单元格列表。
- 使用
-
解析每个单元格:
- 对于每个单元格,检查是否有
< >
符号用于引用其他单元格。 - 解析引用,并递归地解决引用的单元格。
- 如果在解析过程中遇到错误(如未匹配的
<
、引用无效的单元格),则返回"-1"
。
- 对于每个单元格,检查是否有
-
输出结果:
- 将解析后的单元格值合并为最终输出的字符串,输出结果。
这个代码遵循了题目中的要求,解决了单元格的引用问题,并保证了对错误情况的正确处理。
题目描述
现有两组服务器A和B,每组有多个算力不同的CPU。定义:
- A组服务器中第
i
个CPU的运算能力为A[i]
。 - B组服务器中第
j
个CPU的运算能力为B[j]
。
为了让两组服务器的总算力相等,允许从每组各选出一个CPU进行一次交换。求两组服务器中,用于交换的CPU的算力,并且要求从A组服务器中选出的CPU,算力尽可能小。
输入描述:
- 第一行输入两个整数
L1
和L2
,分别表示A组和B组服务器中的CPU数量。 - 第二行输入
L1
个整数,表示A组服务器中各个CPU的算力值,以空格分隔。 - 第三行输入
L2
个整数,表示B组服务器中各个CPU的算力值,以空格分隔。
输出描述:
- 输出两个整数,以空格分隔,依次表示A组选出的CPU算力,B组选出的CPU算力。要求从A组选出的CPU的算力尽可能小。
示例
输入:
2 2
1 1
2 2
输出:
1 2
说明:
从A组中选出算力为1的CPU,与B组中算力为2的进行交换,使两组服务器的算力都等于3。
输入:
2 2
1 2
2 3
输出:
1 2
输入:
1 2
2
1 3
输出:
2 3
输入:
3 2
1 2 5
2 4
输出:
5 4
Java 解题代码
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class ServerSwap {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Read the number of CPUs in each group
int L1 = scanner.nextInt();
int L2 = scanner.nextInt();
// Read the CPU capabilities of group A
int[] A = new int[L1];
for (int i = 0; i < L1; i++) {
A[i] = scanner.nextInt();
}
// Read the CPU capabilities of group B
int[] B = new int[L2];
for (int i = 0; i < L2; i++) {
B[i] = scanner.nextInt();
}
// Close the scanner
scanner.close();
// Calculate total capabilities
int sumA = 0;
for (int a : A) {
sumA += a;
}
int sumB = 0;
for (int b : B) {
sumB += b;
}
// Calculate the required swap difference
int targetDifference = (sumB - sumA) / 2;
// Store A set for fast lookup
Set<Integer> setA = new HashSet<>();
for (int a : A) {
setA.add(a);
}
// Find the pair (a, b) such that b - a = targetDifference
int resultA = -1;
int resultB = -1;
for (int b : B) {
if (setA.contains(b - targetDifference)) {
resultA = b - targetDifference;
resultB = b;
break;
}
}
// Print the result
if (resultA != -1 && resultB != -1) {
System.out.println(resultA + " " + resultB);
} else {
System.out.println("No valid pair found");
}
}
}
代码解释
-
输入读取:
- 使用
Scanner
从标准输入读取数据,解析服务器CPU的数量及其算力。
- 使用
-
计算总算力:
- 计算A组和B组的总算力。
-
计算目标差值:
- 目标差值是
(sumB - sumA) / 2
,这是为了确保在交换时两组服务器的总算力可以相等。
- 目标差值是
-
查找交换对:
- 使用一个哈希集合来存储A组的CPU算力,以便快速查找。
- 遍历B组的每个CPU,检查其是否与A组中的某个CPU配对可以实现目标差值的交换。
-
输出结果:
- 输出满足条件的交换对,确保A组选择的CPU算力最小。
题目描述
智能手机方便了我们的生活,也可能让我们花费过多时间在应用上。为了帮助用户合理规划使用时间,我们需要实现一个“手机App防沉迷系统”。系统的基本功能如下:
- 在一天24小时内,可以注册每个App的允许使用时段。
- 一个时间段只能使用一个App。
- App有优先级,数值越高,优先级越高。注册使用时段时,如果高优先级的App时间和低优先级的时段有冲突,则系统会自动注销低优先级的时段。如果App的优先级相同,则后添加的App不能注册。
- 根据输入的时间点,返回时间点使用的App名称。如果该时间点没有注册任何App,则返回“NA”。
输入描述:
- 第一行表示注册的App数量
N
(N ≤ 100
)。 - 接下来
N
行,每行表示一条App注册数据,格式为:App名称 优先级 起始时间 结束时间
。 - 最后一行输入一个时间点,程序将返回该时间点使用的App。
数据说明:
优先级
为1~5
,数字越大优先级越高。- 时间格式为
HH:MM
,小时和分钟都是两位,不足两位前面补0。 - 起始时间需小于结束时间,否则注册不上。
- 注册信息中的时间段包含起始时间点,不包含结束时间点。
输出描述:
- 输出一个字符串,表示在该时间点使用的App名称,或者“NA”表示该时间点没有注册任何App。
示例
输入:
2
App1 1 09:00 10:00
App2 2 09:10 09:30
09:20
输出:
App2
说明:
App1
和 App2
的时段有冲突,App2
优先级高,因此注册 App2
之后,App1
自动注销。因此输出 App2
。
输入:
2
App1 1 09:00 10:00
App2 2 09:10 09:30
09:50
输出:
NA
说明:
09:50
时间点没有任何注册的App在该时段。
Java 解题代码
import java.util.*;
public class AppScheduler {
static class App {
String name;
int priority;
int startTime;
int endTime;
App(String name, int priority, String startTime, String endTime) {
this.name = name;
this.priority = priority;
this.startTime = timeToMinutes(startTime);
this.endTime = timeToMinutes(endTime);
}
}
private static int timeToMinutes(String time) {
String[] parts = time.split(":");
return Integer.parseInt(parts[0]) * 60 + Integer.parseInt(parts[1]);
}
private static String findAppForTime(List<App> apps, String queryTime) {
int queryMinutes = timeToMinutes(queryTime);
App resultApp = null;
for (App app : apps) {
if (app.startTime <= queryMinutes && queryMinutes < app.endTime) {
if (resultApp == null || app.priority > resultApp.priority) {
resultApp = app;
}
}
}
return resultApp != null ? resultApp.name : "NA";
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Read number of apps
int n = Integer.parseInt(scanner.nextLine().trim());
// List to hold apps
List<App> apps = new ArrayList<>();
// Read app data
for (int i = 0; i < n; i++) {
String[] parts = scanner.nextLine().split(" ");
String name = parts[0];
int priority = Integer.parseInt(parts[1]);
String startTime = parts[2];
String endTime = parts[3];
apps.add(new App(name, priority, startTime, endTime));
}
// Read the query time
String queryTime = scanner.nextLine().trim();
// Determine the app to output
String result = findAppForTime(apps, queryTime);
// Print result
System.out.println(result);
}
}
代码解释
-
App 类:定义一个内部静态类
App
来表示每个应用的名称、优先级、起始时间和结束时间。 -
时间转换函数:
timeToMinutes
将时间字符串转换为分钟数,方便比较。 -
查找合适的应用:
findAppForTime
遍历所有应用,找到在查询时间点有效的应用,并根据优先级选择最高的应用。
-
输入读取和处理:
- 从
Scanner
读取数据,存储应用信息到列表中。 - 调用
findAppForTime
方法确定结果并输出。
- 从
该程序能够处理应用注册、优先级排序以及时间点查询,确保根据给定的时间点正确返回应用名称。
标签:输出,系列,String,int,算法,new,输入,scanner From: https://www.cnblogs.com/mingyu15/p/18353708