2024.08.14 用友笔试-2-Java

P1887财务报表分析

单调栈--leetcode 739.每日温度(例题)

小友正在优化财务报表分析功能。给定一个由不同整数构成的数组revenues,每个元素表示在不同时间段内的收入。

我们用以下方式定义一个与revenues长度相同的数组maxDurations:

maxDurations[i]:是一个子数组revenues[l...r] 的最大长度,该子数组中的最大收入等于revenues[i]。

返回数组 maxDurations。

注意,子数组是数组的连续部分。

输入描述

第一行输入n,表示数组的长度

输入长度为n的数组的各个元素

输出描述

maxDurations

样例

输入

6
1 3 2 4 3 5

输出

1 3 1 5 1 6

说明

对于 revenues[0],最长的子数组,其中最大值为 1,是 nums[0..0],所以 maxDurations[0]=1。
对于 revenues[1],最长的子数组,是 revenues[0..2],其中最大值为 3,所以 maxDurations[1]= 3。
对于 revenues[2],最长的子数组,是 revenues[2..2],其中最大值为 2,所以 maxDurations[2]=1.
对于 revenues[3],最长的子数组,是revenues[0..4],其中最大值为4,所以maxDurations[3]=5
对于 revenues[4],最长的子数组,是 nums[4..4],其中最大值为 3,所以 maxDurations[4]=1
对于 revenues[5],最长的子数组,是 nums[0..5],其中最大值为5,所以 maxDurations[5]=6。

import java.util.*;

public class MaxDurationsCalculator {

    public static int[] maxDurations(int[] revenues) {
        int n = revenues.length;
        int[] left = new int[n];
        int[] right = new int[n];
        int[] maxDurations = new int[n];

        // 初始化 right 数组
        Arrays.fill(right, n); // 如果右侧没有比当前大的元素,则右边界设为 n
        // 初始化 left 数组
        Arrays.fill(left, -1); // 如果左侧没有比当前大的元素,则左边界设为 -1

        // Step 1: 计算右侧边界
        Deque<Integer> stack = new ArrayDeque<>();
        for (int i = 0; i < n; i++) {
            while (!stack.isEmpty() && revenues[stack.peek()] < revenues[i]) {
                right[stack.pop()] = i;
            }
            stack.push(i);
        }

        // Step 2: 计算左侧边界
        stack.clear();
        for (int i = n - 1; i >= 0; i--) {
            while (!stack.isEmpty() && revenues[stack.peek()] <= revenues[i]) {
                left[stack.pop()] = i;
            }
            stack.push(i);
        }

        // Step 3: 计算 maxDurations 数组
        for (int i = 0; i < n; i++) {
            maxDurations[i] = right[i] - left[i] - 1;
        }

        return maxDurations;
    }

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

        for (int i = 0; i < n; i++) {
            revenues[i] = scanner.nextInt();
        }

        int[] result = maxDurations(revenues);

        for (int duration : result) {
            System.out.print(duration + " ");
        }
        System.out.println();
    }
}

P1888电力供应网络

bfs--leetcode 1162.地图分析(例题)

小友负责维护公司的电力供应网络。公司由 n*n 的网格组成,每个单元格代表一个区域,区域中有些有电力设施(用1表示),有些则没有(用0表示)。为了保证公司的电力供应,必须让每个没有电力设施的区域能够尽量靠近一个有电力设施的区域。

你需要找到一个没有电力设施的区域,这个区域到最近的有电力设施的区域的距离是最大的,并返回该举例。如果整个公司都是有电力设施的区域或者没有电力设施的区域,请返回-1。

注意:(x0,y0)和 (x1,y1)这两个区城之间的距离是 |x0-x1| + |y0-y1|。

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Scanner;

public class SpreadSimulation {
    static Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) {
        int gridSize = scanner.nextInt(); // 读取网格大小
        int[][] grid = new int[gridSize][gridSize]; // 初始化网格
        Deque<int[]> queue = new ArrayDeque<>(); // 用于存储起始点的队列

        // 读取网格的初始状态并找到所有的起始点
        for (int row = 0; row < gridSize; row++) {
            for (int col = 0; col < gridSize; col++) {
                grid[row][col] = scanner.nextInt();
                if (grid[row][col] == 1) {
                    queue.offer(new int[]{row, col, 0}); // 将起始点添加到队列
                }
            }
        }

        // 如果没有起始点或整个网格已被占据,直接输出-1
        if (queue.isEmpty() || queue.size() == gridSize * gridSize) {
            System.out.println(-1);
            return;
        }

        int maxDistance = 0; // 用于存储传播的最大距离
        int[][] directions = {{0, 1}, {0, -1}, {-1, 0}, {1, 0}}; // 四个方向

        // 广度优先搜索(BFS)遍历网格,计算最大传播距离
        while (!queue.isEmpty()) {
            int[] current = queue.poll(); // 取出队列中的第一个元素
            int currentX = current[0];
            int currentY = current[1];
            int distance = current[2];

            maxDistance = Math.max(maxDistance, distance); // 更新最大距离

            // 尝试向四个方向扩展
            for (int[] dir : directions) {
                int newX = currentX + dir[0];
                int newY = currentY + dir[1];

                // 如果新位置超出网格边界或已经被占据,则跳过
                if (newX < 0 || newX >= gridSize || newY < 0 || newY >= gridSize || grid[newX][newY] == 1) {
                    continue;
                }

                grid[newX][newY] = 1; // 标记新位置为占据状态
                queue.offer(new int[]{newX, newY, distance + 1}); // 将新位置加入队列,距离加1
            }
        }

        // 输出最大传播距离
        System.out.println(maxDistance);
    }
}

P1889汽车比赛

小友参加了一场汽车长途比赛,比赛从起点开车出发,行至目的地。包括起点、目的地在内,道路上有若干加油站。起点满油出发。车在不同的加油站加油,最终到达目的地。请问小友需要加多少次油才能到达目的地?小友只能在通过的加油站中选择一个加油站加油。

贪心

贪心加油。

由于加油站已经按距离排序,如果发现到达不了某个加油站,说明油不够,我们从最大堆中选加油最多的加油站加一次油。

如果所有加油站都能达到,但还是到达不了终点,仍旧贪心地从最大堆中选加油最多地加油站加油,直到能够达到终点为止。

import java.util.*;

public class RaceFueling {

    public static int minRefuelStops(int target, int startFuel, int[][] stations) {
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
        int fuelStops = 0, currentPosition = 0, currentFuel = startFuel;
        int i = 0;

        while (currentPosition < target) {
            // 计算当前能到达的距离
            int nextStationDistance = (i < stations.length) ? stations[i][0] : target;
            int distanceToTravel = nextStationDistance - currentPosition;

            // 如果油量不足以到达下一站,尝试加油
            while (currentFuel < distanceToTravel && !maxHeap.isEmpty()) {
                currentFuel += maxHeap.poll();
                fuelStops++;
            }

            // 如果仍然无法到达下一站,则无法完成比赛
            if (currentFuel < distanceToTravel) {
                return -1;
            }

            // 更新当前位置和燃料
            currentFuel -= distanceToTravel;
            currentPosition = nextStationDistance;

            // 加油站加油
            if (i < stations.length) {
                maxHeap.offer(stations[i][1]);
                i++;
            }
        }

        return fuelStops;
    }

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

        int target = Integer.parseInt(scanner.nextLine());
        int startFuel = Integer.parseInt(scanner.nextLine());

        List<int[]> stationsList = new ArrayList<>();
        String station;
        while (scanner.hasNextLine()) {
            station = scanner.nextLine().trim();
            if (!station.isEmpty()) {
                String[] stationData = station.split(",");
                stationsList.add(new int[]{Integer.parseInt(stationData[0]), Integer.parseInt(stationData[1])});
            } else {
                break;
            }
        }
        int[][] stations = stationsList.toArray(new int[0][]);
        int result = minRefuelStops(target, startFuel, stations);
        System.out.println(result);
    }
}

P1890消消乐

深度优先搜索--leetcode 488.祖玛游戏 

小友在部门团建中参与了一款消消乐游戏,该游戏规则如下:

  • 桌子上有一排动物图案,分别是猫"C",狗"D",狮子"L",猴子"M",鸟"B"。

  • 小友的手里有一些对应的动物图案,小友的日标是清空桌子上的所有图案

  • 每一回合,从小友手中的图案中任选一个,插入桌子的图案中,可以插入在两个图案之间或一排图案的两端

  • 在插入图案之后,如果有出现三个或者三个以上图案相同且相连的情况,则将他们移除

  • 如果移除图案后,再次出现三个或者三个以上图案相同且相连的情况,则可以继续移除这些图案,直到不再满条件

  • 如果桌面上的图案均被移除,则认为小友获得了胜利

  • 重复上述过程,直至图案全被移除或小友手中没有图案

给定两个字符串,分别表示桌面上初始图案排布情况和小友手里的图案,请你帮小友计算如果按照上还步骤移除桌面上所有的图案,所需要最少的图享数量,如果无法移除所有的图案,则返回-1

import java.util.HashMap;
import java.util.Map;

import java.util.Scanner;

public class RemoveAnimalsGame {

    public static int findMinStep(String board, String hand) {
        Map<Character, Integer> handCount = new HashMap<>();
        for (char c : hand.toCharArray()) {
            handCount.put(c, handCount.getOrDefault(c, 0) + 1);
        }
        int result = dfs(board, handCount);
        return result == Integer.MAX_VALUE ? -1 : result;
    }

    private static int dfs(String board, Map<Character, Integer> handCount) {
        board = removeConsecutive(board);
        if (board.isEmpty()) return 0;
        int minStep = Integer.MAX_VALUE;
        for (int i = 0; i < board.length(); i++) {
            char c = board.charAt(i);
            if (i > 0 && board.charAt(i) == board.charAt(i - 1)) continue; // 跳过重复计算的情况

            if (handCount.getOrDefault(c, 0) > 0) {
                handCount.put(c, handCount.get(c) - 1);
                int step = dfs(board.substring(0, i) + c + board.substring(i), handCount);
                if (step != Integer.MAX_VALUE) {
                    minStep = Math.min(minStep, step + 1);
                }
                handCount.put(c, handCount.get(c) + 1); // 回溯
            }
        }
        return minStep;
    }

    private static String removeConsecutive(String board) {
        int n = board.length();
        for (int i = 0, j = 0; i < n; i = j) {
            while (j < n && board.charAt(i) == board.charAt(j)) j++;
            if (j - i >= 3) return removeConsecutive(board.substring(0, i) + board.substring(j));
        }
        return board;
    }

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

        //输入桌面上的图案分布
        String board = scanner.nextLine();

        //请输入小友手中的图案
        String hand = scanner.nextLine();

        int result = findMinStep(board, hand);
        System.out.println(result);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值