首页 > 编程语言 >算法题系列5

算法题系列5

时间:2024-08-11 18:17:22浏览次数:8  
标签:输出 系列 String int 算法 new 输入 scanner

题目描述
模拟一套简化的序列化传输方式,请实现下面的数据编码与解码过程

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代码示例。

编码说明

  1. 输入格式:

    • [位置,类型,值],其中 位置 是一个数字,类型 可以是 IntegerStringCompose 对应不同的 类型,如果 类型Compose 本身也是一个 [位置,类型,值] 的列表。
  2. 编码规则:

    • 对于 Integer 类型,编码格式为 位置#0#长度#数据
    • 对于 String 类型,编码格式为 位置#1#长度#数据
    • 对于 Compose 类型,编码格式为 位置#2#长度#数据,其中 数据 是嵌套的编码结果。

解码说明

  1. 输入格式:

    • 数据区的格式为 位置#类型#长度#数据
  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();
    }
}

代码解释

  1. 编码函数:

    • 将输入的格式解析为 位置#类型#长度#数据 的形式。
    • 对于 Compose 类型,递归编码内部的结构。
  2. 解码函数:

    • 解析编码后的数据区,根据 类型 还原原始格式。
    • 处理嵌套的 Compose 类型,递归解码。
  3. 错误处理:

    • 编码和解码过程中的格式错误都被捕获并标记为 ENCODE_ERRORDECODE_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:
        • XY 是基站编号。
        • Z 是架设光纤的成本。
        • P 表示是否已存在光纤连接(1表示已连接,0表示未连接)。
  • 目标:

    • 找到最小的建设成本使所有基站互联。
    • 如果无法实现互联,则输出 -1。

解决方案

  1. 构建图:

    • 将所有光纤连接(包括已存在的和需要建设的)转换成边的形式 (成本, 起点, 终点)
    • 已存在的光纤连接(P = 1)的成本为 0。
  2. 应用 Kruskal's 算法:

    • 排序: 按边的成本排序。
    • 并查集: 用于检测环路并合并不同的集合。
    • 选边: 逐步选择成本最小的边,确保选取的边不会形成环路,直到所有基站都被连接。
  3. 判断:

    • 如果在构建最小生成树的过程中,不能连接所有基站,则返回 -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
        }
    }
}

代码解释

  1. 输入处理:

    • 读取输入数据并构造 Edge 对象。
    • 对于已存在的光纤连接,将其成本设置为 0。
  2. Kruskal's 算法:

    • 排序边按照成本。
    • 使用并查集(Union-Find)结构来管理连通性。
    • 遍历边,选择未形成环路的边来加入最小生成树。
  3. 结果判断:

    • 如果成功连接所有基站,则返回总成本;否则返回 -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

输出描述
一个数字。代表歌手最多

要解决这个问题,我们需要设计一个动态规划算法来最大化歌手在规定天数内的总收入。我们将采用动态规划来解决这个问题,因为我们需要考虑不同城市之间的旅行时间以及在城市中卖唱的收益随时间的变化。

动态规划思路

  1. 定义状态:

    • dp[i][t] 表示在第 i 座城市并且已经用 t 天的情况下,能获得的最大收入。
  2. 状态转移:

    • 从城市 j 移动到城市 i 的时间为 time[j][i]。我们可以在城市 jk 天后再出发。

    • 在城市 jk 天的收入是: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 是在城市 jk 天获得的收入。

  3. 初始化:

    • dp[i][t] 需要初始化为非常小的值(负无穷),因为我们要找的是最大值。
    • 在城市 i 到达时的初始收入是 0,因为没有时间在城市中待过。
  4. 边界条件:

    • 从任何城市到达城市 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);
    }
}

代码解释

  1. 输入处理:

    • 读取天数 T 和城市数量 N
    • 读取每两座城市之间的旅行时间和每个城市的卖唱预期数据。
  2. 动态规划表初始化:

    • dp[i][t] 表示到达城市 i 并且已经用 t 天的情况下的最大收入。
  3. 动态规划计算:

    • 遍历每座城市的每一天,更新 dp 表格。
  4. 结果输出:

    • 输出在所有时间中获得的最大收入。

注意事项

  • 确保考虑所有可能的天数 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。下面是一个详细的算法步骤和实现。

算法步骤

  1. 数据表示:

    • 记录每种阶数的信道数量。
    • 计算每种阶数信道的容量。
    • 将所有信道的容量存储在一个列表中,方便后续处理。
  2. 背包问题转化:

    • 每个用户的需求可以视作一个背包问题,其中每个信道的容量是背包中物品的重量。
    • 目标是找到最小的背包组合,使其总容量不小于 D
  3. 动态规划:

    • 使用动态规划来解决变体背包问题,计算达到或超过 D 的最小信道组合。
    • 通过一个布尔数组 dp 来记录是否可以用 i 个信道的组合满足需求 D
  4. 计算最大用户数:

    • 根据可用信道的数量和每个用户所需信道的数量,计算最多可以服务的用户数。

动态规划实现

以下是完整的 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);
    }
}

代码解释

  1. 输入处理:

    • 读取最大阶数 R 和每种阶数的信道数量。
    • 计算每种信道的容量(2^r),并将所有信道的容量存储在 channelList 中。
  2. 动态规划:

    • 初始化 dp 数组,dp[i] 表示用最少的信道数达到 i 比特的容量。
    • 遍历所有信道容量,更新 dp 数组来计算达到至少 D 比特所需的最小信道数。
  3. 计算结果:

    • 找到达到 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
这个问题可以通过模拟按要求从多个列表中选择元素来完成。为了实现题目描述中的需求,我们需要遵循以下步骤:

  1. 解析输入

    • 读取窗口数量 N 和每个窗口的大小 K
    • 读取每个列表的元素,直到所有列表读取完毕。
  2. 均分处理

    • 将每个列表的元素尽量均分为 N 份。如果某个列表的元素数量不足 N,那么剩余的元素需要根据实际情况填充到窗口中。
  3. 按顺序选择元素

    • 按照顺序,从每个列表中选出元素填充到每个窗口中,确保每个窗口的元素来自于不同的列表。
  4. 生成输出

    • 将每个窗口的元素按照顺序拼接成输出格式。

实现步骤

  1. 读取和解析输入

    • 首先读取 NK,然后读取各个列表的元素。
  2. 分配列表元素

    • 将每个列表的元素分配到窗口中。如果某个列表的元素数量不足 N,需要将其余的元素根据实际情况分配到窗口中。
  3. 输出结果

    • 将每个窗口的元素按照顺序输出。

以下是实现代码:

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) + " ");
                }
            }
        }
    }
}

代码解释

  1. 输入读取

    • 从标准输入中读取 NK,然后读取多个列表的数据。
  2. 处理列表

    • 对每个列表中的元素按窗口的顺序进行分配。由于需要处理均分的情况,因此每个列表的元素被均匀地分配到窗口中。
  3. 生成输出

    • 按要求将每个窗口的元素输出到标准输出中。

注意事项

  • 确保正确处理列表的边界情况,例如列表长度不足 N 的情况。
  • 确保输出格式符合要求,尤其是每个窗口元素的顺序。

这个解决方案通过模拟分配过程,确保了按照要求将元素分配到每个窗口中,并且考虑了多种情况。


题目描述

  1. 老李是货运公司承运人,老李的货车额定载货重量为 wt
  2. 现有两种货物,货物A单件重量为 wa,单件运费利润为 pa,货物B单件重量为 wb,单件运费利润为 pb
  3. 老李每次发车时载货总重量刚好为货车额定载货重量 wt,车上必须同时有货物A和货物B,货物A、B不可切割。
  4. 老李单车次满载运输可获得的最高利润是多少?

输入描述:

  • 第一列输入为货物A的单件重量 wa0 < wa < 10000
  • 第二列输入为货物B的单件重量 wb0 < wb < 10000
  • 第三列输入为货车的额定载重 wt0 < wt < 100000
  • 第四列输入为货物A的单件运费利润 pa0 < pa < 1000
  • 第五列输入为货物B的单件运费利润 pb0 < 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);
    }
}

代码解释

  1. 读取输入

    • 使用 Scanner 读取五个输入值,分别代表货物A的单件重量、货物B的单件重量、货车的额定载重、货物A的单件运费利润、货物B的单件运费利润。
  2. 计算最大利润

    • 遍历所有可能的货物A的数量 countA
    • 对于每一种可能的 countA,计算剩余重量 remainingWeight
    • 检查剩余重量是否能被货物B的重量整除。
    • 计算当前方案的利润,并更新最大利润。
  3. 输出结果

    • 打印最大利润。


题目描述

一根 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 + " ");
        }
    }
}

代码解释

  1. 初始化

    • 使用 dp 数组来保存每个长度木材的最大收益。
    • 使用 cuts 列表来保存每个长度木材对应的最佳切割方案。
  2. 计算最大收益

    • 对于每种可能的长度 i,尝试从 1i / 2 的所有切割方案。
    • 计算每种切割方案的收益,更新 dp[i]cuts[i]
  3. 输出结果

    • 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();
    }
}

代码解释

  1. 读取输入

    • 使用 Scanner 从标准输入读取单行数据,并将其按逗号分隔成单元格列表。
  2. 解析每个单元格

    • 对于每个单元格,检查是否有 < > 符号用于引用其他单元格。
    • 解析引用,并递归地解决引用的单元格。
    • 如果在解析过程中遇到错误(如未匹配的 <、引用无效的单元格),则返回 "-1"
  3. 输出结果

    • 将解析后的单元格值合并为最终输出的字符串,输出结果。

这个代码遵循了题目中的要求,解决了单元格的引用问题,并保证了对错误情况的正确处理。


题目描述

现有两组服务器A和B,每组有多个算力不同的CPU。定义:

  • A组服务器中第i个CPU的运算能力为 A[i]
  • B组服务器中第j个CPU的运算能力为 B[j]

为了让两组服务器的总算力相等,允许从每组各选出一个CPU进行一次交换。求两组服务器中,用于交换的CPU的算力,并且要求从A组服务器中选出的CPU,算力尽可能小。

输入描述:

  • 第一行输入两个整数L1L2,分别表示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");
        }
    }
}

代码解释

  1. 输入读取

    • 使用 Scanner 从标准输入读取数据,解析服务器CPU的数量及其算力。
  2. 计算总算力

    • 计算A组和B组的总算力。
  3. 计算目标差值

    • 目标差值是 (sumB - sumA) / 2,这是为了确保在交换时两组服务器的总算力可以相等。
  4. 查找交换对

    • 使用一个哈希集合来存储A组的CPU算力,以便快速查找。
    • 遍历B组的每个CPU,检查其是否与A组中的某个CPU配对可以实现目标差值的交换。
  5. 输出结果

    • 输出满足条件的交换对,确保A组选择的CPU算力最小。


题目描述

智能手机方便了我们的生活,也可能让我们花费过多时间在应用上。为了帮助用户合理规划使用时间,我们需要实现一个“手机App防沉迷系统”。系统的基本功能如下:

  1. 在一天24小时内,可以注册每个App的允许使用时段。
  2. 一个时间段只能使用一个App。
  3. App有优先级,数值越高,优先级越高。注册使用时段时,如果高优先级的App时间和低优先级的时段有冲突,则系统会自动注销低优先级的时段。如果App的优先级相同,则后添加的App不能注册。
  4. 根据输入的时间点,返回时间点使用的App名称。如果该时间点没有注册任何App,则返回“NA”。

输入描述:

  • 第一行表示注册的App数量 NN ≤ 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

说明:

App1App2 的时段有冲突,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);
    }
}

代码解释

  1. App 类:定义一个内部静态类 App 来表示每个应用的名称、优先级、起始时间和结束时间。

  2. 时间转换函数timeToMinutes 将时间字符串转换为分钟数,方便比较。

  3. 查找合适的应用

    • findAppForTime 遍历所有应用,找到在查询时间点有效的应用,并根据优先级选择最高的应用。
  4. 输入读取和处理

    • Scanner 读取数据,存储应用信息到列表中。
    • 调用 findAppForTime 方法确定结果并输出。

该程序能够处理应用注册、优先级排序以及时间点查询,确保根据给定的时间点正确返回应用名称。



标签:输出,系列,String,int,算法,new,输入,scanner
From: https://www.cnblogs.com/mingyu15/p/18353708

相关文章

  • 用电量预测 | 基于BiLSTM双向长短期记忆神经网络算法的用电量预测附matlab完整代码
    用电量预测|基于BiLSTM双向长短期记忆神经网络算法的用电量预测附matlab完整代码数据收集:收集历史用电量数据,包括时间戳和相应的用电量值。选择模型:选择合适的模型进行预测,可以根据数据特点和需求选择合适的模型。训练模型:使用历史数据训练模型,并根据评估指标来调整......
  • 【WSN覆盖优化】基于鱼鹰优化算法OOA求解无线传感器节点2D覆盖优化问题附Matlab代码
    鱼鹰优化算法(OspreyOptimizationAlgorithm,OOA)是一种基于鱼鹰捕鱼行为的启发式优化算法,可用于解决优化问题。在无线传感器网络(WSN)中,覆盖优化是一个关键问题,涉及到最大化网络覆盖范围并减少节点数量。以下是一个简单的示例框架,展示如何基于OOA算法求解无线传感器节点的二......
  • 什么是算法
    1.概述算法指的是为了完成某一事情(或者解决某一问题),而经过特定步骤的处理之后得到结果的一种手段具有明确的步骤/顺序/可行性计算机擅长做固定的运算,例如求和等计算型的处理,通过合适的算法(合适的处理策略),可以大大降低运算所需要的时间2.举例为了对数字进行排序......
  • 算法笔记|Day22回溯算法IV
    算法笔记|Day22回溯算法IV☆☆☆☆☆leetcode491.递增子序列题目分析代码☆☆☆☆☆leetcode46.全排列题目分析代码☆☆☆☆☆leetcode47.全排列II题目分析代码☆☆☆☆☆leetcode332.重新安排行程(待补充)题目分析代码☆☆☆☆☆leetcode51.N皇后(待补充)题目分析......
  • 【1.0版】【MYSQL安全】sql注入系列:基于报错的 SQL 盲注
    主题sql注入:基于报错的SQL盲注一、Floor报错注入1.1floor函数1.2rand函数1.3count(*)1.4floor函数实际利用二、extractvalue函数三、updatexml函数:同extractvalue本来网页是不显示信息的,但是我们可以构造payload让信息通过错误提示回显出......
  • 【WSN覆盖优化】基于斑马优化算法ZOA求解无线传感器节点2D覆盖优化问题附Matlab代码
    以下是一个简单的示例Matlab代码,演示如何使用斑马优化算法(ZebraOptimizationAlgorithm,ZOA)来解决无线传感器节点(WSN)的2D覆盖优化问题:ini复制%ZebraOptimizationAlgorithm(ZOA)forWirelessSensorNetwork(WSN)CoverageOptimization%设置参数num_nodes=50;......
  • 探索Python中的插入排序算法
    探索Python中的插入排序算法插入排序(InsertionSort)是一种简单直观的排序算法。虽然在大规模数据集上效率不如一些高级排序算法,但插入排序在处理小规模数据集或部分有序的数据时表现非常优秀。本文将介绍插入排序的工作原理、实现方法以及它的时间复杂度。插入排序的工作......
  • Dijkstra算法
    Dijkstra算法是一种用于在加权图中寻找单源最短路径的算法。它由荷兰计算机科学家EdsgerDijkstra在1956年提出。该算法基于贪心策略,通过不断选择当前最短路径上的顶点来逐步确定最短路径。它使用一个距离数组来记录起始点到每个顶点的距离,并使用一个集合来存储已经求得最短路......
  • 图像分割算法
    5.1阈值分割(Thresholding)介绍阈值分割是一种简单而有效的图像分割方法,通过设置一个或多个阈值,将图像分割为前景和背景区域。常见的阈值分割方法包括全局阈值、自适应阈值和Otsu阈值。原理阈值分割通过比较像素值与设定的阈值,将像素分类为前景或背景。公式在阈值分割......
  • 499 道 Java 面试题 (附答案):JVM+ 分布式 + 算法 + 锁 +MQ
    Spring如何管理事务的。Spring怎么配置事务(具体说出一些关键的xml元素)。说说你对Spring的理解,非单例注入的原理?它的生命周期?循环注入的原理,aop的实现原理,说说aop中的几个术语,它们是怎么相互工作的。Springmvc中DispatcherServlet初始化过程。netty......