java解一些算法题-不一定正确哈

题目描述
某部门计划通过结队编程来进行项目开发,已知该部门有 N 名员工,每个员工有独一无二的职级,每三个员工形成一个小组进行结队编程。

结队分组规则如下: 从部门中选出序号分别为i、j、k 的 3 名员工,他们的职级分别为 level[i], level[j], level[k]

结队小组需满足 level[i] < level[j] < level[k] 或者 level[i] > level[j] > level[k] ,其中 0 ⩽ i < j < k < n 请你按上述条件计算可能组合的小组数量。

同一员工可以参加多个小组。

输入
第一行输入:员工总数 n

第二行输入:按序号依次排列的员工的职级 level,中间用空格隔开

限制:

1 ⩽ n ⩽ 6000

1 ⩽ level[i] ⩽ 10^5

输出
可能组合的小组数量
样例输入 复制
4
1 2 3 4
样例输出 复制
4
提示
可能结队成的组合 (1,2,3)、(1,2,4)、(1,3,4)、(2,3,4)。

import java.util.Scanner;

public class TripletCounter {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取员工总数
        int n = scanner.nextInt();
        
        // 读取员工的职级
        int[] levels = new int[n];
        for (int i = 0; i < n; i++) {
            levels[i] = scanner.nextInt();
        }
        
        // 计算并输出可能组合的小组数量
        int result = countTriplets(levels);
        System.out.println(result);
    }

    private static int countTriplets(int[] levels) {
        int n = levels.length;
        int count = 0;
        
        for (int i = 0; i < n - 2; i++) {
            for (int j = i + 1; j < n - 1; j++) {
                for (int k = j + 1; k < n; k++) {
                    if ((levels[i] < levels[j] < levels[k]) || (levels[i] > levels[j] > levels[k])) {
                        count++;
                    }
                }
            }
        }
        
        return count;
    }
}

题目描述
在一个机房中,服务器的位置标识在 n*m 的整数矩阵网格中,1 表示单元格上有服务器,0 表示没有。如果两台服务器位于同一行或者同一列中紧邻的位置,则认为它们之间可以组成一个局域网。

请你统计机房中最大的局域网包含的服务器个数。

输入描述
第一行输入两个正整数,n和m,0<n,m<=100

之后为n*m的二维数组,代表服务器信息

输出描述
最大局域网包含的服务器个数。

用例
输入 2 2
1 0
1 1
输出 3
说明 [0][0]、[1][0]、[1][1]三台服务器相互连接,可以组成局域网

import java.util.Scanner;

public class LargestNetwork {
    private static int n, m;
    private static int[][] grid;
    private static boolean[][] visited;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取 n 和 m
        n = scanner.nextInt();
        m = scanner.nextInt();
        
        // 初始化网格和访问标记数组
        grid = new int[n][m];
        visited = new boolean[n][m];
        
        // 读取网格数据
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                grid[i][j] = scanner.nextInt();
            }
        }
        
        int maxNetworkSize = 0;
        
        // 遍历网格,查找最大的局域网
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 1 && !visited[i][j]) {
                    int networkSize = dfs(i, j);
                    maxNetworkSize = Math.max(maxNetworkSize, networkSize);
                }
            }
        }
        
        // 输出结果
        System.out.println(maxNetworkSize);
    }

    // 深度优先搜索方法,返回局域网大小
    private static int dfs(int x, int y) {
        // 定义移动方向:上、下、左、右
        int[] dx = {-1, 1, 0, 0};
        int[] dy = {0, 0, -1, 1};
        
        visited[x][y] = true;
        int size = 1;
        
        // 遍历四个方向
        for (int i = 0; i < 4; i++) {
            int newX = x + dx[i];
            int newY = y + dy[i];
            
            if (isValid(newX, newY) && grid[newX][newY] == 1 && !visited[newX][newY]) {
                size += dfs(newX, newY);
            }
        }
        
        return size;
    }

    // 检查坐标是否有效
    private static boolean isValid(int x, int y) {
        return x >= 0 && x < n && y >= 0 && y < m;
    }
}

题目描述
有一棵二叉树,每个节点由一个大写字母标识(最多26个节点)。

现有两组字母,分别表示后序遍历(左孩子->右孩子->父节点)和中序遍历(左孩子->父节点->右孩子)的结果,请输出层次遍历的结果。

输入描述
输入为两个字符串,分别是二叉树的后续遍历和中序遍历结果。

输出描述
输出二叉树的层次遍历结果。

示例1
输入:
CBEFDA CBAEDF

输出:
ABDCEF

说明:
二叉树为:
A
/
B D
/ /
C E F

import java.util.*;

class TreeNode {
    char val;
    TreeNode left;
    TreeNode right;
    
    TreeNode(char x) {
        val = x;
    }
}

public class BinaryTreeTraversal {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取后序遍历和中序遍历字符串
        String postorder = scanner.next();
        String inorder = scanner.next();
        
        // 构建二叉树
        TreeNode root = buildTree(postorder, inorder);
        
        // 层次遍历二叉树并输出结果
        String levelOrder = levelOrderTraversal(root);
        System.out.println(levelOrder);
    }

    // 从后序遍历和中序遍历构建二叉树
    private static TreeNode buildTree(String postorder, String inorder) {
        if (postorder == null || inorder == null || postorder.length() != inorder.length()) {
            return null;
        }
        
        Map<Character, Integer> inorderMap = new HashMap<>();
        for (int i = 0; i < inorder.length(); i++) {
            inorderMap.put(inorder.charAt(i), i);
        }
        
        return buildTreeHelper(postorder, 0, postorder.length() - 1, inorder, 0, inorder.length() - 1, inorderMap);
    }

    private static TreeNode buildTreeHelper(String postorder, int postStart, int postEnd, 
                                            String inorder, int inStart, int inEnd, 
                                            Map<Character, Integer> inorderMap) {
        if (postStart > postEnd || inStart > inEnd) {
            return null;
        }
        
        char rootVal = postorder.charAt(postEnd);
        TreeNode root = new TreeNode(rootVal);
        
        int inorderRootIndex = inorderMap.get(rootVal);
        int leftTreeSize = inorderRootIndex - inStart;
        
        root.left = buildTreeHelper(postorder, postStart, postStart + leftTreeSize - 1, 
                                    inorder, inStart, inorderRootIndex - 1, inorderMap);
        root.right = buildTreeHelper(postorder, postStart + leftTreeSize, postEnd - 1, 
                                     inorder, inorderRootIndex + 1, inEnd, inorderMap);
        
        return root;
    }

    // 层次遍历二叉树
    private static String levelOrderTraversal(TreeNode root) {
        if (root == null) {
            return "";
        }
        
        StringBuilder result = new StringBuilder();
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            result.append(node.val);
            
            if (node.left != null) {
                queue.offer(node.left);
            }
            
            if (node.right != null) {
                queue.offer(node.right);
            }
        }
        
        return result.toString();
    }
}

// refer: https://csproject.icu/index.php/archives/107/
题目描述
一个局域网内有很多台电脑,分别标注为 0 ~ N-1 的数字。相连接的电脑距离不一样,所以感染时间不一样,感染时间用 t 表示。

其中网络内一台电脑被病毒感染,求其感染网络内所有的电脑最少需要多长时间。如果最后有电脑不会感染,则返回-1。

给定一个数组 times 表示一台电脑把相邻电脑感染所用的时间。

如图:path[i] = {i, j, t} 表示:电脑 i->j,电脑 i 上的病毒感染 j,需要时间 t。

输入描述
4
3
2 1 1
2 3 1
3 4 1
2
输出描述
2
示例:

输入 4
3
2 1 1
2 3 1
3 4 1
2
输出 2
说明 第一个参数:局域网内电脑个数N,1 ≤ N ≤ 200;
第二个参数:总共多少条网络连接
第三个 2 1 1 表示2->1时间为1
第六行:表示病毒最开始所在电脑号2

import java.util.*;

public class NetworkInfection {
    public static int minInfectionTime(int N, int[][] times, int start) {
        // 构建图
        Map<Integer, List<int[]>> graph = new HashMap<>();
        for (int i = 0; i < N; i++) {
            graph.put(i, new ArrayList<>());
        }
        for (int[] time : times) {
            graph.get(time[0]).add(new int[]{time[1], time[2]});
        }

        // Dijkstra算法
        int[] minTime = new int[N];
        Arrays.fill(minTime, Integer.MAX_VALUE);
        minTime[start] = 0;

        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));
        pq.add(new int[]{start, 0});

        while (!pq.isEmpty()) {
            int[] curr = pq.poll();
            int u = curr[0];
            int timeU = curr[1];

            if (timeU > minTime[u]) continue;

            for (int[] neighbor : graph.get(u)) {
                int v = neighbor[0];
                int timeUV = neighbor[1];
                if (minTime[u] + timeUV < minTime[v]) {
                    minTime[v] = minTime[u] + timeUV;
                    pq.add(new int[]{v, minTime[v]});
                }
            }
        }

        int maxTime = 0;
        for (int time : minTime) {
            if (time == Integer.MAX_VALUE) return -1;
            maxTime = Math.max(maxTime, time);
        }

        return maxTime;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int N = scanner.nextInt();
        int M = scanner.nextInt();
        int[][] times = new int[M][3];
        for (int i = 0; i < M; i++) {
            times[i][0] = scanner.nextInt();
            times[i][1] = scanner.nextInt();
            times[i][2] = scanner.nextInt();
        }
        int start = scanner.nextInt();

        int result = minInfectionTime(N, times, start);
        System.out.println(result);
    }
}

题目描述
给定一个乱序的数组,删除所有的重复元素,使得每个元素只出现一次,并且按照出现的次数从高到低进行排序,相同出现次数按照第一次出现顺序进行先后排序。
输入
一个数组
输出
去重排序后的数组
样例输入 复制
1,3,3,3,2,4,4,4,5
样例输出 复制
3,4,1,2,5
提示
数组大小不超过100,数组元素值大小不超过100

import java.util.*;

public class RemoveDuplicatesAndSort {
    public static List<Integer> removeDuplicatesAndSort(int[] nums) {
        // 统计每个数字出现的频率,并保持第一次出现的顺序
        LinkedHashMap<Integer, Integer> frequencyMap = new LinkedHashMap<>();
        for (int num : nums) {
            frequencyMap.put(num, frequencyMap.getOrDefault(num, 0) + 1);
        }

        // 将频率map转换为列表进行排序
        List<Map.Entry<Integer, Integer>> entryList = new ArrayList<>(frequencyMap.entrySet());
        
        // 按频次从高到低排序,频次相同的按第一次出现的顺序
        entryList.sort((e1, e2) -> {
            int freqCompare = e2.getValue().compareTo(e1.getValue());
            if (freqCompare != 0) {
                return freqCompare;
            } else {
                // 由于LinkedHashMap保持了插入顺序,这里相同频次按插入顺序即可
                return 0;
            }
        });

        // 提取排序后的键
        List<Integer> result = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : entryList) {
            result.add(entry.getKey());
        }

        return result;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        String[] inputStrings = input.split(",");
        int[] nums = new int[inputStrings.length];
        for (int i = 0; i < inputStrings.length; i++) {
            nums[i] = Integer.parseInt(inputStrings[i]);
        }

        List<Integer> result = removeDuplicatesAndSort(nums);
        for (int num : result) {
            System.out.print(num + " ");
        }
    }
}

题目描述
给定一段”密文”字符串s,其中字符都是经过”密码本”映射的,现需要将”密文”解密并且输出。

映射的规则 :"a-i"分别用"1-9"表示,"j-z" 分别用"10-26"表示

约束:映射始终唯一

输入描述
“密文”字符串

输出描述
明文字符串

补充说明
翻译后的文本的长度在100以内

示例一
输入
201920*
Bash
输出
tst

import java.util.Scanner;

public class DecryptMessage {
    public static String decrypt(String s) {
        StringBuilder result = new StringBuilder();
        int length = s.length();
        int i = 0;

        while (i < length) {
            // Check for '*', indicating a two-character mapping
            if (i + 2 < length && s.charAt(i + 2) == '*') {
                int num = Integer.parseInt(s.substring(i, i + 2));
                result.append((char) ('a' + num - 1));
                i += 3; // Move past this mapping
            } else {
                // Single character mapping
                int num = s.charAt(i) - '0';
                result.append((char) ('a' + num - 1));
                i += 1; // Move past this mapping
            }
        }

        return result.toString();
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        String result = decrypt(input);
        System.out.println(result);
    }
}

题目描述:

公司用一个字符串来表示员工的出勤信息:
absent:缺勤
late:迟到
leaveearly:早退
present:正常上班
现需根据员工出勤信息,判断本次是否能获得出勤奖,能获得出勤奖的条件如下:
缺勤不超过一次;没有连续的迟到/早退;任意连续7次考勤,缺勤/迟到/早退不超过3次
输入描述:

用户的考勤数据字符串,记录条数 >= 1;输入字符串长度<10000;不存在非法输入

如:

2

present

present absent present present leaveearly present absent

输出描述:

根据考勤数据字符串,如果能得到考勤奖,输出"true";否则输出"false",对于输入示例的结果应为:

true false

示例1

输入:

2
present
present present
输出:

true true
说明:

示例2

输入:

2
present
present absent present present leaveearly present absent
输出:

true false

import java.util.Scanner;

public class AttendanceAward {

    // 检查考勤记录是否符合奖励条件
    public static boolean checkAttendance(String[] attendance) {
        // 检查缺勤次数是否超过一次
        int absentCount = 0;
        for (String record : attendance) {
            if (record.equals("absent")) {
                absentCount++;
            }
        }
        if (absentCount > 1) {
            return false;
        }

        // 检查是否有连续迟到/早退
        for (int i = 1; i < attendance.length; i++) {
            if ((attendance[i].equals("late") || attendance[i].equals("leaveearly")) &&
                (attendance[i-1].equals("late") || attendance[i-1].equals("leaveearly"))) {
                return false;
            }
        }

        // 检查任意连续7天的考勤记录中,缺勤/迟到/早退次数不超过3次
        for (int i = 0; i <= attendance.length - 7; i++) {
            int count = 0;
            for (int j = i; j < i + 7; j++) {
                if (attendance[j].equals("absent") || attendance[j].equals("late") || attendance[j].equals("leaveearly")) {
                    count++;
                }
            }
            if (count > 3) {
                return false;
            }
        }

        return true;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取测试用例数
        int testCases = scanner.nextInt();
        scanner.nextLine(); // 消耗换行符

        // 处理每个测试用例
        for (int t = 0; t < testCases; t++) {
            String[] attendance = scanner.nextLine().split(" ");
            boolean result = checkAttendance(attendance);
            System.out.println(result);
        }
    }
}

题目描述
现有若干个会议,所有会议共享一个会议室,用数组表示各个会议的开始时间和结束时间,

格式为: [[会议1开始时间,会议1结束时间],[会议2开始时间,会议2结束时间]] 请计算会议室占用时间段。

输入描述
[[会议1开始时间,会议1结束时间],[会议2开始时间,会议2结束时间] ]

备注:

会议个数范围: [1,100]

会议室时间段: [1,24]

输出描述
输出格式预输入一致,具体请看用例。

[[会议开始时间,会议结束时间],[会议开始时间,会议结束时间]

示例1
输入:
[[1,4], [2,5],[7,9], [14,18]]

输出:
[[1,5], [7,9],[14,18]]

说明:
时间段[1,4]和[2,5]重叠,合并为[1,5]
示例2
输入:
[[1 ,4],[4,5]]

输出:
[[1,5]]

import java.util.*;

public class MeetingScheduler {
    public static List<int[]> mergeIntervals(int[][] intervals) {
        // 1. 如果没有会议记录,则返回空列表
        if (intervals.length == 0) {
            return new ArrayList<>();
        }

        // 2. 将二维数组转为List方便操作
        List<int[]> intervalsList = new ArrayList<>(Arrays.asList(intervals));

        // 3. 按照开始时间排序
        intervalsList.sort(Comparator.comparingInt(a -> a[0]));

        // 4. 合并时间段
        List<int[]> merged = new ArrayList<>();
        int[] currentInterval = intervalsList.get(0);
        merged.add(currentInterval);

        for (int i = 1; i < intervalsList.size(); i++) {
            int[] nextInterval = intervalsList.get(i);
            // 如果当前时间段的结束时间大于等于下一个时间段的开始时间,则有重叠
            if (currentInterval[1] >= nextInterval[0]) {
                // 合并时间段
                currentInterval[1] = Math.max(currentInterval[1], nextInterval[1]);
            } else {
                // 不重叠,保存当前时间段,并开始处理下一个时间段
                currentInterval = nextInterval;
                merged.add(currentInterval);
            }
        }

        return merged;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 读取输入,处理格式为 [[1,4], [2,5], ...]
        String input = scanner.nextLine();
        // 处理输入格式
        input = input.replace("[[", "[").replace("]]", "]").replace("],[", "] [");
        String[] parts = input.split(" ");
        List<int[]> intervals = new ArrayList<>();

        for (String part : parts) {
            String[] range = part.replace("[", "").replace("]", "").split(",");
            int start = Integer.parseInt(range[0]);
            int end = Integer.parseInt(range[1]);
            intervals.add(new int[]{start, end});
        }

        // 合并时间段
        List<int[]> mergedIntervals = mergeIntervals(intervals.toArray(new int[0][]));

        // 输出结果
        StringBuilder result = new StringBuilder("[");
        for (int i = 0; i < mergedIntervals.size(); i++) {
            int[] interval = mergedIntervals.get(i);
            if (i > 0) {
                result.append(", ");
            }
            result.append("[").append(interval[0]).append(", ").append(interval[1]).append("]");
        }
        result.append("]");
        System.out.println(result.toString());
    }
}

题目描述
部门在进行需求开发时需要进行人力安排。

当前部门需要完成 N 个需求,需求用 requirements 表述,requirements[i] 表示第 i 个需求的工作量大小,单位:人月。

这部分需求需要在 M 个月内完成开发,进行人力安排后每个月人力时固定的。

目前要求每个月最多有2个需求开发,并且每个月需要完成的需求不能超过部门人力。

请帮助部门评估在满足需求开发进度的情况下,每个月需要的最小人力是多少?

输入描述
输入为 M 和 requirements,M 表示需求开发时间要求,requirements 表示每个需求工作量大小,N 为 requirements长度,

1 ≤ N/2 ≤ M ≤ N ≤ 10000
1 ≤ requirements[i] ≤ 10^9
输出描述
对于每一组测试数据,输出部门需要人力需求,行末无多余的空格

用例
输入

3
3 5 3 4
输出

6
说明

输入数据两行, 第一行输入数据3表示开发时间要求, 第二行输入数据表示需求工作量大小, 输出数据一行,表示部门人力需求。 当选择人力为6时,2个需求量为3的工作可以在1个月里完成,其他2个工作各需要1个月完成。可以在3个月内完成所有需求。 当选择人力为5时,4个工作各需要1个月完成,一共需要4个月才能完成所有需求。 因此6是部门最小的人力需求。

import java.util.*;

public class MinimumHumanResource {

    // 检查在指定人力限制下是否可以在 M 个月内完成所有需求
    private static boolean canCompleteInMonths(int[] requirements, int months, int maxHuman) {
        int currentMonth = 1;
        int currentLoad = 0;
        int count = 0;
        
        while (count < requirements.length) {
            if (currentLoad + requirements[count] <= maxHuman) {
                currentLoad += requirements[count];
                count++;
            } else {
                // 如果当前月的需求超出人力限制,分配到下一个月
                currentMonth++;
                if (currentMonth > months) {
                    return false;
                }
                currentLoad = 0;
            }
        }
        
        return true;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取开发时间要求 M
        int M = scanner.nextInt();
        scanner.nextLine(); // 处理换行符
        
        // 读取需求工作量
        String[] requirementsStr = scanner.nextLine().split(" ");
        int[] requirements = new int[requirementsStr.length];
        for (int i = 0; i < requirementsStr.length; i++) {
            requirements[i] = Integer.parseInt(requirementsStr[i]);
        }
        
        // 二分查找最小人力需求
        int left = 1; // 人力资源最小为 1
        int right = Arrays.stream(requirements).max().getAsInt(); // 人力资源最大为单个需求的最大值
        
        while (left < right) {
            int mid = (left + right) / 2;
            if (canCompleteInMonths(requirements, M, mid)) {
                right = mid; // 尝试更小的人力
            } else {
                left = mid + 1; // 增加人力资源
            }
        }
        
        System.out.println(left);
    }
}

题目描述
马是象棋(包括中国象棋只和国际象棋)中的棋子,走法是每步直一格再斜一格,即先横着或直着走一格,然后再斜着走一个对角线,可进可退,可越过河界,俗称马走 “日“ 字。

给项m行n列的棋盘(网格图),棋盘上只有象棋中的棋子“马”,并目每个棋子有等级之分,等级为K的马可以跳1~k步(走的方式与象棋中“马”的规则一样,不可以超出棋盘位置),问是否能将所有马跳到同一位置,如果存在,输出最少需要的总步数(每匹马的步数相加) ,不存在则输出-1。

注:允许不同的马在跳的过程中跳到同一位置,坐标为(x,y)的马跳一次可以跳到到坐标为(x+1,y+2),(x+1,y-2),(x+2,y+1),(x+2,y-1). (x-1,y+2),(x-1,y-2),(x-2,y+1),(x-2,y-1),的格点上,但是不可以超出棋盘范围。

输入描述
第一行输入m,n代表m行n列的网格图棋盘(1 <= m,n <= 25);

接下来输入m行n列的网格图棋盘,如果第i行,第j列的元素为 “.” 代表此格点没有棋子,如果为数字k (1<= k <=9),代表此格点存在等级为的“马”。

输出描述
输出最少需要的总步数 (每匹马的步数相加),不存在则输出-1。

示例1
输入:
3 2
..
2.
..

输出:
0
示例2
输入:
3 5
47.48
4744.
7....

输出:
17

import java.util.*;

public class HorseChessboard {

    // 马的所有可能移动
    private static final int[][] MOVES = {
        {1, 2}, {1, -2}, {-1, 2}, {-1, -2},
        {2, 1}, {2, -1}, {-2, 1}, {-2, -1}
    };

    // 检查坐标是否在棋盘内
    private static boolean isValid(int x, int y, int m, int n) {
        return x >= 0 && x < m && y >= 0 && y < n;
    }

    // BFS计算从start到所有其他点的最短路径
    private static int[][] bfs(int startX, int startY, int m, int n) {
        int[][] dist = new int[m][n];
        for (int[] row : dist) Arrays.fill(row, Integer.MAX_VALUE);
        Queue<int[]> queue = new LinkedList<>();
        queue.add(new int[]{startX, startY});
        dist[startX][startY] = 0;

        while (!queue.isEmpty()) {
            int[] pos = queue.poll();
            int x = pos[0], y = pos[1];
            int currentDist = dist[x][y];

            for (int[] move : MOVES) {
                int newX = x + move[0];
                int newY = y + move[1];
                if (isValid(newX, newY, m, n) && dist[newX][newY] == Integer.MAX_VALUE) {
                    dist[newX][newY] = currentDist + 1;
                    queue.add(new int[]{newX, newY});
                }
            }
        }

        return dist;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取棋盘的行列数
        int m = scanner.nextInt();
        int n = scanner.nextInt();
        scanner.nextLine(); // 读取换行符

        // 读取棋盘数据
        char[][] board = new char[m][n];
        List<int[]> horses = new ArrayList<>();
        for (int i = 0; i < m; i++) {
            String line = scanner.nextLine();
            for (int j = 0; j < n; j++) {
                board[i][j] = line.charAt(j);
                if (board[i][j] != '.') {
                    horses.add(new int[]{i, j, board[i][j] - '0'}); // 记录马的位置及等级
                }
            }
        }

        // 检查每个位置作为目标点,计算最小总步数
        int minSteps = Integer.MAX_VALUE;
        for (int targetX = 0; targetX < m; targetX++) {
            for (int targetY = 0; targetY < n; targetY++) {
                boolean valid = true;
                int totalSteps = 0;
                
                for (int[] horse : horses) {
                    int startX = horse[0];
                    int startY = horse[1];
                    int level = horse[2];
                    
                    int[][] dist = bfs(startX, startY, m, n);
                    if (dist[targetX][targetY] == Integer.MAX_VALUE || dist[targetX][targetY] > level) {
                        valid = false;
                        break;
                    }
                    totalSteps += dist[targetX][targetY];
                }

                if (valid) {
                    minSteps = Math.min(minSteps, totalSteps);
                }
            }
        }

        // 输出结果
        if (minSteps == Integer.MAX_VALUE) {
            System.out.println(-1);
        } else {
            System.out.println(minSteps);
        }
    }
}

题目描述
在某个项目中有多个任务(用tasks数组表示)需要您进行处理,其中tasks[i]=[si,ei],你可以在si <= day <= ei中的任意一天处理该任务,请返回你可以处理的最大任务数

输入描述
第一行为任务数量n,1 <=n<= 100000。后面n行表示各个任务的开始时间和终止时间,使用si,ei表示,1 <= si <= ei <= 100000

输出描述
输出为一个整数,表示可以处理的最大任务数。

用例
输入

3
1 1
1 2
1 3
输出

3

import java.util.*;

public class TaskScheduler {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取任务数量
        int n = scanner.nextInt();
        scanner.nextLine(); // 消耗换行符

        // 读取所有任务
        List<int[]> tasks = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            int start = scanner.nextInt();
            int end = scanner.nextInt();
            scanner.nextLine(); // 消耗换行符
            tasks.add(new int[]{start, end});
        }
        
        // 按结束时间排序
        tasks.sort(Comparator.comparingInt(a -> a[1]));

        // 选择任务
        int maxTasks = 0;
        int lastEndTime = 0;
        
        for (int[] task : tasks) {
            int start = task[0];
            int end = task[1];
            
            // 选择任务条件:任务开始时间不早于上一个选择任务的结束时间
            if (start > lastEndTime) {
                maxTasks++;
                lastEndTime = end;
            }
        }
        
        // 输出结果
        System.out.println(maxTasks);
    }
}

题目描述
有一个考古学家发现一个石碑,但是很可惜,发现时其已经断成多段,原地发现n个断口整齐的石碑碎片。

为了破解石碑内容,考古学家希望有程序能帮忙计算复原后的石碑文字组合数,你能帮忙吗?

输入描述
第一行输入 n
n表示石碑碎片的个数
第二行依次输入石碑碎片上的文字内容s,共有n组。

输出描述
输出石碑文字的组合(按照升序排列),行末无多余空格。

备注
如果存在石碑碎片内容完全相同,则由于碎片间的顺序变换不影响复原后的碑文内容,即相同碎片间的位置变换不影响组合。

用例
输入
3
a b c
输出
abc
acb
bac
bca
cab
cba
说明
当石碑碎片上的内容为“a”,“b”,“c”时,则组合有“abc”,“acb”,“bac”,“bca”,“cab”,“cba”

import java.util.*;

public class StoneTablet {

    // 生成所有排列的方法
    private static void generatePermutations(List<String> fragments, List<String> results, int start) {
        if (start == fragments.size() - 1) {
            results.add(String.join("", fragments));
            return;
        }
        
        for (int i = start; i < fragments.size(); i++) {
            Collections.swap(fragments, start, i);
            generatePermutations(fragments, results, start + 1);
            Collections.swap(fragments, start, i); // 回溯
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取碎片数量
        int n = scanner.nextInt();
        scanner.nextLine(); // 消耗换行符

        // 读取碎片内容
        List<String> fragments = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            fragments.add(scanner.next());
        }

        // 生成所有排列
        List<String> results = new ArrayList<>();
        generatePermutations(fragments, results, 0);

        // 对结果进行排序
        Collections.sort(results);

        // 输出结果
        for (String result : results) {
            System.out.println(result);
        }
    }
}

题目描述:
有位客人来自异国,在该国使用m进制计数。该客人有个幸运数字n(n<m),每次购物时,其总是喜欢计算本次支付的花费(折算为异国的价格后)中存在多少幸运数字。问:当其购买一个在我国价值k的产品时,其中包含多少幸运数字?

输入描述:

第一行输入为 k, n, m。

其中:

k 表示 该客人购买的物品价值(以十进制计算的价格)

n 表示 该客人的幸运数字

m 表示 该客人所在国度的采用的进制

输出描述:

输出幸运数字的个数,行末无空格。

补充说明:

当输入非法内容时,输出0

示例1

输入:

10 2 4

输出:

2

说明:

10用4进制表示时为22,同时,异国客人的幸运数字是2,故而此处输出为2,表示有2个幸运数字。

示例2

输入:

10 4 4

输出:

0

说明:

此时客人的幸运数字为4,但是由于该国最大为4进制,故而在该国的进制下不可能出现幸运数字,故而返回0

import java.util.Scanner;

public class LuckyNumberCounter {

    // 将十进制数字转换为指定进制的字符串
    private static String convertToBase(int number, int base) {
        if (number == 0) {
            return "0";
        }
        StringBuilder result = new StringBuilder();
        while (number > 0) {
            int remainder = number % base;
            result.append(remainder);
            number /= base;
        }
        return result.reverse().toString();
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取输入
        int k = scanner.nextInt();
        int n = scanner.nextInt();
        int m = scanner.nextInt();

        // 输入合法性检查
        if (k < 0 || n < 0 || n >= m || m <= 1) {
            System.out.println(0);
            return;
        }

        // 转换为指定进制
        String kInBaseM = convertToBase(k, m);

        // 统计幸运数字出现的次数
        String luckyDigit = Integer.toString(n);
        int count = 0;
        for (char c : kInBaseM.toCharArray()) {
            if (Character.getNumericValue(c) == n) {
                count++;
            }
        }

        // 输出结果
        System.out.println(count);
    }
}

题目描述:

Wonderland是小王居住地一家很受欢迎的游乐园。Wonderland目前有 4 种售票方式,分别为一日票(天)、三日票(3 天),周票( 7 天)和月票( 30 天) 。每种售票方式的价格由一个数组给出,每种票据在票面时限内可以无限制地进行游玩。

例如:小王在第10日买了一张三日票,小王可以在第10日、第11日和第12日进行无限制地游玩,小王计划在接下来玩计划所需要地最低消费。小王一年多次游玩该游乐园。小王计划地游玩日期将由一个数组给出。

现在,请您根据给出地售票价格数组和小王计划游玩日期数组,返回游玩计划所需要地最低消费。

输入描述

输入第一行为售票价格数组 costs ;

输入第二行为小王计划游玩日期数组 days\ncosts.length = 4,默认顺序为一日票、三日票、周票和月票。

1< = days.length < = 365,1< = days[i]< = 365 ,默认顺序为升序.

输出描述

完成游玩计划的最低消费

示例1:

输入:

5 14 30 100

1 3 5 20 21 200 202 230

输出:

40

说明:

根据售票价格数组和游玩日期数组给出的信息,发现每次去玩的时候买一张一日票是最省钱的,所以小王会买 8张一日票,每张 5 元,最低花费是 40 元。

import java.util.*;

public class Wonderland {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取票价
        int[] costs = new int[4];
        for (int i = 0; i < 4; i++) {
            costs[i] = scanner.nextInt();
        }
        scanner.nextLine(); // 消耗换行符

        // 读取游玩日期
        List<Integer> daysList = new ArrayList<>();
        while (scanner.hasNextInt()) {
            daysList.add(scanner.nextInt());
        }
        
        int[] days = daysList.stream().mapToInt(i -> i).toArray();
        
        // 动态规划数组
        int maxDay = days[days.length - 1];
        int[] dp = new int[maxDay + 1];
        Arrays.fill(dp, Integer.MAX_VALUE);
        dp[0] = 0;

        // 游玩日期集合,用于快速查找
        Set<Integer> daysSet = new HashSet<>();
        for (int day : days) {
            daysSet.add(day);
        }

        for (int i = 1; i <= maxDay; i++) {
            if (daysSet.contains(i)) {
                dp[i] = Math.min(dp[i], dp[i - 1] + costs[0]);
                if (i >= 3) dp[i] = Math.min(dp[i], dp[i - 3] + costs[1]);
                if (i >= 7) dp[i] = Math.min(dp[i], dp[i - 7] + costs[2]);
                if (i >= 30) dp[i] = Math.min(dp[i], dp[i - 30] + costs[3]);
            } else {
                dp[i] = dp[i - 1];
            }
        }

        // 输出结果
        System.out.println(dp[maxDay]);
    }
}

题目描述
从前有个村庄,村民们喜欢在各种田地上插上小旗子,旗子上标识了各种不同的数字。

某天集体村民决定将覆盖相同数字的最小矩阵形的土地分配给村里做出巨大贡献的村民,请问此次分配土地,做出贡献的村民种最大会分配多大面积?

输入描述
第一行输入 m 和 n,

m 代表村子的土地的长
n 代表土地的宽
第二行开始输入地图上的具体标识

输出描述
此次分配土地,做出贡献的村民种最大会分配多大面积

备注
旗子上的数字为1~500,土地边长不超过500
未插旗子的土地用0标识
用例
输入 3 3
1 0 1
0 0 0
0 1 0
输出 9
说明 土地上的旗子为1,其坐标分别为(0,0),(2,1)以及(0,2),为了覆盖所有旗子

import java.util.Scanner;

public class FlagArea {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取输入
        int m = scanner.nextInt();
        int n = scanner.nextInt();
        scanner.nextLine(); // 消耗换行符

        int[][] map = new int[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                map[i][j] = scanner.nextInt();
            }
            scanner.nextLine(); // 消耗换行符
        }

        // 使用 Map 来存储每种数字的最小和最大坐标
        int[][] minRow = new int[501][2]; // minRow[i][0] = min row, minRow[i][1] = max row
        int[][] minCol = new int[501][2]; // minCol[i][0] = min col, minCol[i][1] = max col

        // 初始化
        for (int i = 0; i < 501; i++) {
            minRow[i][0] = m; // Set minRow to a large number initially
            minRow[i][1] = -1; // Set maxRow to a small number initially
            minCol[i][0] = n; // Set minCol to a large number initially
            minCol[i][1] = -1; // Set maxCol to a small number initially
        }

        // 查找每个数字的边界
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                int num = map[i][j];
                if (num > 0) {
                    if (i < minRow[num][0]) minRow[num][0] = i;
                    if (i > minRow[num][1]) minRow[num][1] = i;
                    if (j < minCol[num][0]) minCol[num][0] = j;
                    if (j > minCol[num][1]) minCol[num][1] = j;
                }
            }
        }

        // 计算最大的面积
        int maxArea = 0;
        for (int i = 1; i < 501; i++) {
            if (minRow[i][1] >= minRow[i][0] && minCol[i][1] >= minCol[i][0]) {
                int width = minCol[i][1] - minCol[i][0] + 1;
                int height = minRow[i][1] - minRow[i][0] + 1;
                int area = width * height;
                if (area > maxArea) maxArea = area;
            }
        }

        // 输出结果
        System.out.println(maxArea);
    }
}

题目描述
小华和小为是很要好的朋友,他们约定周末一起吃饭。

通过手机交流,他们在地图上选择了多个聚餐地点(由于自然地形等原因,部分聚餐地点不可达)。

求小华和小为都能到达的聚餐地点有多少个?

输入描述
第一行输入m和n,m代表地图的长度,n代表地图的宽度

第二行开始具体输入地图信息,地图信息包含:

0 为通畅的道路

1 为障碍物 (且仅1为障碍物)

2 为小华或者小为,地图中必定有且仅有2个(非障碍物)

3 为被选中的聚餐地点 (非障碍物)

输出描述
可以被两方都到达的聚餐地点数量,行末无空格

示例1
输入:
4 4
2 1 0 3
0 1 2 1
0 3 0 0
0 0 0 0

输出:
2

说明:第一行输入地图的长宽为4,4,接下来4行是地图2表示华为的位置,3是聚餐地点,图中的两个3,小华和小为都可到达,所以输出2
示例2
输入
4 4
2 1 2 3
0 1 0 0
0 1 0 0
0 1 0 0

输出
0

import java.util.*;

public class DiningSpots {

    private static final int[] DIRS = {0, 1, 0, -1, 1, 0, -1, 0}; // 四个方向: 上, 下, 左, 右
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取地图的尺寸
        int m = scanner.nextInt();
        int n = scanner.nextInt();
        scanner.nextLine(); // 消耗换行符
        
        int[][] map = new int[m][n];
        int[] start1 = new int[2]; // 小华的位置
        int[] start2 = new int[2]; // 小为的位置
        Set<int[]> spots = new HashSet<>(); // 聚餐地点的集合
        
        // 读取地图数据
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                map[i][j] = scanner.nextInt();
                if (map[i][j] == 2) {
                    if (start1[0] == 0 && start1[1] == 0) {
                        start1[0] = i;
                        start1[1] = j;
                    } else {
                        start2[0] = i;
                        start2[1] = j;
                    }
                } else if (map[i][j] == 3) {
                    spots.add(new int[] {i, j});
                }
            }
            scanner.nextLine(); // 消耗换行符
        }
        
        // BFS 函数
        boolean[][] visited1 = bfs(map, start1[0], start1[1], m, n);
        boolean[][] visited2 = bfs(map, start2[0], start2[1], m, n);
        
        // 统计可以被两方都到达的聚餐地点
        int count = 0;
        for (int[] spot : spots) {
            int x = spot[0];
            int y = spot[1];
            if (visited1[x][y] && visited2[x][y]) {
                count++;
            }
        }
        
        // 输出结果
        System.out.println(count);
    }
    
    // 执行 BFS 搜索
    private static boolean[][] bfs(int[][] map, int startX, int startY, int m, int n) {
        boolean[][] visited = new boolean[m][n];
        Queue<int[]> queue = new LinkedList<>();
        queue.offer(new int[] {startX, startY});
        visited[startX][startY] = true;
        
        while (!queue.isEmpty()) {
            int[] cur = queue.poll();
            int x = cur[0];
            int y = cur[1];
            
            for (int i = 0; i < 4; i++) {
                int newX = x + DIRS[i * 2];
                int newY = y + DIRS[i * 2 + 1];
                
                if (isValid(newX, newY, m, n) && !visited[newX][newY] && map[newX][newY] != 1) {
                    visited[newX][newY] = true;
                    queue.offer(new int[] {newX, newY});
                }
            }
        }
        
        return visited;
    }
    
    // 检查坐标是否在地图范围内
    private static boolean isValid(int x, int y, int m, int n) {
        return x >= 0 && x < m && y >= 0 && y < n;
    }
}

posted @ 2024-08-06 18:07  MingYu15  阅读(60)  评论(0)    收藏  举报