【2】好未来JAVA开发工程师部分笔试题解析

编程题

1.降序的子数组最大元素和

给你一个正整数组成的数组nums,返回nums中一个降序子数组的最大可能元素和。

子数组是数组中的一个连续数字序列。

已知子数组[nums l, nums l+1, … , nums r-1, nums r],若对所有l (1<=i<r),nums i>nums i+1都成立,则称这一子数组为降序子数组。注意,大小为1的子数组也视作降序子数组。

补充说明

1 <= nums.length <= 100

1<= nums[i]<= 100

示例1

输入

[50,10,20,30,5,10]

输出

60

说明

[50,10]是元素和最大的降序子数组,最大元素和为60。

示例2

输入

[50,30,20]

输出

100

说明
[50,30,20]是元素和最大的降序子数组,最大元素和为100。

题解
import java.util.Scanner;

public class Main{
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);

        int n = scanner.nextInt();

        int[] arr = new int[n];
        // temp 用于临时存储当前递减子序列的和
        int temp = 0;
        // sum 用于存储最大的递减子序列的和,最终结果
        int sum = 0;


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


        // ptrIndex 作为指针,遍历数组 arr
        int ptrIndex = 0;
        // 当指针 ptrIndex 还在数组范围内时,循环继续
        while (ptrIndex <= n - 1) {
            // 将当前指针指向的元素值赋给 temp,作为当前递减子序列的起始值
            temp = arr[ptrIndex];

            // 内层循环:寻找从 ptrIndex 开始的最长递减子序列
            while (ptrIndex < n - 1 && arr[ptrIndex] > arr[ptrIndex + 1]) {
                ptrIndex++;
                // 将新的元素值加到 temp 中,更新当前递减子序列的和
                temp += arr[ptrIndex];
            }
            // 递减子序列结束,指针向后移动一位,开始寻找下一个递减子序列
            ptrIndex++;

            //更新最大的递减子序列的和 sum
            if (sum < temp) {
                sum = temp;
            }
        }

        System.out.println(sum);

        scanner.close();
    }
}

2.覆盖房屋的最小加热半径(leetcode475)

冬季已经来临。你的任务是设计一个有固定加热半径的供暖器向所有房屋供暖。
在加热器的加热半径范围内的每个房屋都可以获得供暖。

现在,给出位于一条水平线上的房屋houses和供暖器heaters的位置,请你找出并返回可以覆盖所有房屋的最小加热半径。

注意

所有供暖器heaters都遵循你的半径标准,加热的半径也—样。

示例1

输入

[1,2,3],[2]

输出

1

示例2

输入

[1,2,3,4],[1,4]

输出

1

题解
import java.util.Arrays;

public class Main{
    public int findRadius(int[] houses, int[] heaters) {
        // 1. 将供暖器位置数组排序,方便使用二分查找
        Arrays.sort(heaters);

        // 2. 初始化最小加热半径为 0
        int radius = 0;

        // 3. 遍历每个房屋
        for (int house : houses) {
            // 4. 使用二分查找找到距离当前房屋最近的供暖器位置
            int heaterIndex = findNearestHeater(heaters, house);

            // 5. 计算当前房屋需要的加热半径
            int currentRadius = Math.abs(heaters[heaterIndex] - house);

            // 6. 更新最小加热半径
            radius = Math.max(radius, currentRadius);
        }

        // 7. 返回最小加热半径
        return radius;
    }

    private int findNearestHeater(int[] heaters, int house) {
        int left = 0;
        int right = heaters.length - 1;
        int ans = 0; //存储下标

        while(left <= right){
            int mid = left + (right - left) / 2;

            if(heaters[mid] == house){
                return mid;
            } else if(heaters[mid] < house){
                left = mid + 1;
            } else {
                right = mid -1;
            }
            ans = left;
        }
        if (ans == 0) {
            return 0;  //房屋在供暖器左侧,第一个供暖器最近
        } else if (ans == heaters.length) {
            return heaters.length - 1; //房屋在所有供暖器右侧,最后一个供暖器最近
        } else {

            //比较房屋到左右两个供暖器的距离,选择最近的供暖器
            if(Math.abs(heaters[ans] - house) < Math.abs(heaters[ans -1] - house)){
                return ans;
            } else {
                return ans -1;
            }

        }

    }
}

3.鸡蛋掉落(leetcode887)

给你k枚相同的鸡蛋,并可以使用一栋从第1层到第n层共有n层楼的建筑。

已知存在楼层f,满足0<=f<=n,任何从高于f的楼层落下的鸡蛋都会碎,从f楼层或比它低的楼层落下的鸡蛋都不会破。

每次操作,你可以取一枚没有碎的鸡蛋并把它从任一楼层x扔下(满足1<=x<=n)。如果鸡蛋碎了,你就不能再次使用它。如果某枚鸡蛋扔下后没有摔碎,则可以在之后的操作中重复使用这枚鸡蛋。

请你计算并返回要确定f确切的值的最小操作次数是多少?

补充说明

提示

1<=k<=100

1<=n<=10^4

示例1

输入

1,2

输出

2

说明

输入:

k=1,n=2

输出:

2

解释

鸡蛋从1楼掉落。如果它碎了,肯定能得出f=0。
否则,鸡蛋从2楼掉落。如果它碎了,肯定能得出f=1。

如果它没碎,那么肯定能得出f=2。
因此,在最坏的情况下我们需要移动2次以确定f是多少。

示例2

输入

2,6

输出

3

示例3

输入

3,14

输出

4

题解
public class Main{
    public int superEggDrop(int k, int n) {
        // dp[i][j] 表示 i 个鸡蛋,j 层楼时,最坏情况下的最少尝试次数
        int[][] dp = new int[k + 1][n + 1];

        // 初始化:
        // 0 层楼,无论多少个鸡蛋,都不需要尝试
        for (int i = 1; i <= k; i++) {
            dp[i][0] = 0;
        }
        // 1 个鸡蛋,j 层楼,最坏情况要尝试 j 次
        for (int j = 1; j <= n; j++) {
            dp[1][j] = j;
        }

        // 状态转移:
        // 从 2 个鸡蛋,2 层楼开始计算
        for (int i = 2; i <= k; i++) {
            for (int j = 1; j <= n; j++) {
                dp[i][j] = Integer.MAX_VALUE; // 初始化为最大值

                // 二分查找优化尝试的楼层,寻找最优解
                int left = 1, right = j;
                while (left <= right) {
                    int mid = left + (right - left) / 2;

                    // 鸡蛋碎了:需要在 mid-1 层楼往下寻找,鸡蛋数量减少 1
                    int broken = dp[i - 1][mid - 1];
                    // 鸡蛋没碎:需要在 j-mid 层楼往上寻找,鸡蛋数量不变
                    int notBroken = dp[i][j - mid];

                    // 取最坏情况下的尝试次数
                    int temp = Math.max(broken, notBroken) + 1;

                    // 更新 dp[i][j],取最小值
                    dp[i][j] = Math.min(dp[i][j], temp);

                    // 二分查找,调整方向
                    if (broken > notBroken) {
                        right = mid - 1; // 碎了的情况代价更大,尝试往低楼层找
                    } else {
                        left = mid + 1; // 没碎的情况代价更大,尝试往高楼层找
                    }
                }
            }
        }

        // 返回 k 个鸡蛋,n 层楼时,最坏情况下的最少尝试次数
        return dp[k][n];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值