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
思路分析
- 对课程进行排序,按照结束时间从小到大,结束时间相同,开始时间从小到大
- 动态规划,遍历所有课程,当前课程有两种选择,选,不选。不选该课程,则
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个单位时间;
- 相同类型任务相继执行需要经过冷却,冷却时间为M个单位时间
求执行完全部任务所需的最短时间
思路分析
我们需要统计任务数最多的任务类型个数count
、最多的任务数maxTaskNum
,可以得到执行完任务数最多的任务所需要的时间为 (maxTaskNum - 1) * (M + 1) + count
,然后比较总任务数 N
和 这些时间
有两种情况
N <= (maxTaskNum - 1) * (M + 1) + count
说明冷却时间里可以将任务数不是最多的任务都执行完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