24.4.14文远知行笔试

4.17 收到感谢信,已凉


文远知行笔试,共三道题,核心代码模式,不支持本地IDE调试,笔试时长2小时,分值各100分。
通过了第二题 5/6 测试用例,a了第3题


第一题 选课最大价值

给定课程,每个课程有开始时间、结束时间、课程价值,表示为(t1, t2, value)。
不能选择时间冲突的课程,求在保证课程不冲突下,上的课可以获得最大的价值

输入:
第一行整数n,表示课程数量
接下去 n 行二维数组,第 i 行 t1, t2, value 表示第 i 门课的开始时间,结束时间,该课程的价值

输出:
最大价值

测试用例:
用例1:
3
1 10 10
3 4 11
4 5 3
用例2:
4
1 3 11
2 4 12
4 6 13
5 6 14
用例3:
4
1 3 13
2 4 12
1 6 20
3 7 5

思路分析

  1. 对课程进行排序,按照结束时间从小到大,结束时间相同,开始时间从小到大
  2. 动态规划,遍历所有课程,当前课程有两种选择,选,不选。不选该课程,则dp[i] = dp[i - 1];选该课程,需要查找前面一个时间不发生冲突的课程,设为index,则dp[i] = dp[index] + courses[i][2],两种情况取最大

代码如下:

import java.util.Arrays;
import java.util.Scanner;

/**
 * @author Joey
 * @version 1.0
 */
public class First {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        //课程数
        int N = in.nextInt();
        //课程 [begin,end,value]
        int[][] courses = new int[N][3];
        for (int i = 0; i < N; i++) {
            courses[i][0] = in.nextInt();
            courses[i][1] = in.nextInt();
            courses[i][2] = in.nextInt();
        }
        int result = solution(courses);

        System.out.println(result);
    }
    private static int solution(int[][] courses) {

        //按照右边界排序
        Arrays.sort(courses, (a,b) -> {
            if (a[1] == b[1]) {
                return a[0] < b[0] ? -1 : 1;
            }
            return a[1] < b[1] ? -1 : 1;
        });

        for (int[] c : courses) {
            System.out.println(Arrays.toString(c));
        }

        int len = courses.length;
        //dp[i] 表示 0-i 下标范围(不含i)的课程不冲突的情况下的最大价值
        //dp 中的 i 表示 courses 中的第 i 个课程
        int[] dp = new int[len + 1];
        dp[0] = 0;
        dp[1] = courses[0][2];
        
        //遍历课程列表
        for (int i = 2; i <= len; i++) { //从 courses 中的第 2 个课程开始遍历
            int num = i - 1; //表示第 i 个课程在 courses 中的下标
            //第 i 个课程的开始时间,大于第 i-1 个课程的结束时间,所以,dp[i] = 前面那个课程能取得最大价值,加上当前课程价值
            if (courses[num][0] >= courses[num - 1][1]) {
                dp[i] = dp[i - 1] + courses[num][2];
            } else { //发生课程冲突
                int index = num - 1; // index 表示第 i-1 个课程的下标
                //往前查找最近的和当前课程时间不冲突的课程下标
                while (index >= 0 && courses[index][1] > courses[num][0]) {
                    index--;
                }
                //不选该课程能获得的最大价值 和 选了该课程能获得的最大价值进行比较,取最大值
                dp[i] = Math.max(dp[i - 1], dp[index + 1] + courses[num][2]);
            }
        }
		//打印 dp 数组
        System.out.println(Arrays.toString(dp));
        return dp[len];
    }
}

难点

如何理解当当前课程和前一个课程发生冲突时,要选当前课程的最大价值的计算方法
因为已经按照结束时间对课程进行排序,当前课程与前一个课程发生冲突,需要往前查找,找到最近的和当前课程不冲突的课程下标 index,所以当前课程的最大价值就是 dp[index +1] + courses[num][2]dp[i]中的i 表示第 i 个课程,同时dp[i]会保证i之前的课程都不冲突。

第二题 CPU工作最短时间

给出工作任务字符串,共有26种不同类型的工作,用大写字母 ‘A-Z’ 表示,工作任务量为N,冷却时间为M,
cpu工作方式如下:

  1. 每个任务执行时间为1个单位时间;
  2. 相同类型任务相继执行需要经过冷却,冷却时间为M个单位时间

求执行完全部任务所需的最短时间

思路分析

我们需要统计任务数最多的任务类型个数count、最多的任务数maxTaskNum,可以得到执行完任务数最多的任务所需要的时间为 (maxTaskNum - 1) * (M + 1) + count,然后比较总任务数 N 和 这些时间
有两种情况

  1. N <= (maxTaskNum - 1) * (M + 1) + count 说明冷却时间里可以将任务数不是最多的任务都执行完
  2. N > (maxTaskNum - 1) * (M + 1) + count 说明冷却时间里不足以执行任务数不是最多的任务,所以还有剩下 left = N - base - count个任务。这里可能会有疑问,要是剩下的这些任务中又引入了新的冷却时间呢,实际上并不会发生,可以将剩下的那些任务,如果任务类型相同,将其穿插到之前任务数最多的任务的执行区间,这样他们的冷却时间足够,但并不会引入新的冷却时间,所以执行剩下的任务所需时间就是left

代码如下:

import java.util.Arrays;
import java.util.Scanner;

/**
 * @author Joey
 * @version 1.0
 */
public class Second {
    /*
测试用例
6 AAABBB 2
9 AAABBBCCC 2
12 AAABBBCCCDDD 2
     */
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int N = in.nextInt();
        String tasks = in.next();
        int M = in.nextInt();

        int result = solution(N, tasks, M);

        System.out.println(result);
    }
    private static int solution(int N, String s, int M) {
        //使用哈希表统计任务数量
        int[][] hash = new int[26][1];
        for (int i = 0; i < s.length(); i++) {
            hash[s.charAt(i) - 'A'][0]++;
        }
        //哈希表排序
        Arrays.sort(hash, (a, b)-> {
            return a[0] > b[0] ? -1 : 1;
        });

        //统计最多任务的类型数量
        int count = 1;
        for (int i = 1; i < 26; i++) {
            if (hash[i][0] == hash[i - 1][0]) {
                count++;
            } else break;
        }
        
        //同一类型任务的最大任务数
        int maxTaskNum = hash[0][0];
        int base = (maxTaskNum - 1) * (M + 1);
        int left = N <= (base + count) ? 0 : (N - base - count);
        return base + count + left;
    }
}

第三题 int型数字反转

给定一个32位有符号整数,求反转后的数,如果反转后溢出,则返回0

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值