08.14 大疆笔试 后端开发工程师(研发部)B卷 AC
最大权重的无重叠取数组
这里,不用列表,单纯记录pre应该也是可以,但是感觉代码比较麻烦,就图省事了,
排序后,对于新来的区间 [start, end],权重 w
dp[end] = Math.max(dp[end_i], dp[start_j] + w)
- end_i 表示小于等于end的最大end
- start_j 表示小于等于start的最大end
例如:
// 排序后 // start end weight [2, 5, 3] [1, 6, 2] [3, 8, 10] [7, 9, 5] [7, 9, 10] // [2, 5, 3] come, create [5, 3, [1]] // list: [5, 3, [1]] // [1, 6, 2] come, create [6, 2, [2]] // choose: [6, 2, [2]] OR [5, 3, [1]] // list: [5, 3, [1]], [6, 3, [1]] // [3, 8, 10] come, create [8, 10, [3]] // choose: [6, 3, [1]] OR [8, 10, [3]] // list: [5, 3, [1]], [6, 3, [1]], [8, 10, [3]] // [7, 9, 5] come, create [9, 5, [4]] // choose: [6, 3, [1]] + [9, 5, [4]] OR [3, 8, [10]] // list: [5, 3, [1]], [6, 3, [1]], [8, 10, [3]], [9, 10, [3]] // [7, 9, 10] come, create [9, 10, [5]] // choose: [6, 3, [1]] + [9, 10, [5]] OR [9, 10, [3]] // list: [5, 3, [1]], [6, 3, [1]], [8, 10, [3]], [9, 13, [1, 5]]
代码
import java.io.*; import java.util.*; import java.text.*; import java.math.*; import java.util.regex.*; class Solution { /* Write Code Here */ public int[] schedule(int[][] arr) { int n = arr.length; // 记录数组对应的下标 Map<int[], Integer> map = new HashMap<>(); for(int i = 0; i < n; i++) { map.put(arr[i], i); } // 根据结束时间排序 Arrays.sort(arr, (a, b) -> a[2]-b[2]); // 结束时间 ArrayList<EndStatus> list = new ArrayList<>(); for(int i = 0; i < n; i++) { EndStatus status = new EndStatus(); if(list.isEmpty()) { status.endTime = arr[i][2]; status.weight = arr[i][0]; status.item = new ArrayList<>(); status.item.add(i); list.add(status); } else if(list.get(0).endTime > arr[i][1]) { // 起始时间小于endTime // 寻找小于等于结束时间的最大的endTime,比较value值 int nextIdx = findIdx(arr[i][2], list); s = list.get(nextIdx); if(s.endTime == status.endTime) { if(s.weight < status.weight) { list.set(nextIdx, status); } }else if(s.weight < status.weight) { list.add(status); }else{ status.weight = s.weight; status.item = s.item; list.add(status); } } else { // 起始时间大于等于endTime // 寻找小于等于起始时间的最大的endTime,计算value值 int preIdx = findIdx(arr[i][1], list); EndStatus s = list.get(preIdx); status.endTime = arr[i][2]; status.weight = arr[i][0] + s.weight; List<Integer> tmp = new ArrayList<>(s.item); tmp.add(i); status.item = tmp; // 寻找小于等于结束时间的最大的endTime,比较value值 int nextIdx = findIdx(arr[i][2], list); s = list.get(nextIdx); if(s.endTime == status.endTime) { if(s.weight < status.weight) { list.set(nextIdx, status); } }else if(s.weight < status.weight) { list.add(status); }else{ status.weight = s.weight; status.item = s.item; list.add(status); } } } int weightv = 0; List<Integer> retList = new ArrayList<>(); for(int i = 0; i < n; i++) { EndStatus s = list.get(i); if(s.weight > weightv) { weightv = s.weight; retList = s.item; } } int ret[] = new int[retList.size()]; for(int i = 0; i < retList.size(); i++){ ret[i] = map.get(arr[retList.get(i)]); } return ret; } private int findIdx(int time, ArrayList<EndStatus> list) { int left = 0, right = list.size()-1; while(left < right) { int mid = (left + right+1) / 2; int tmpTime = list.get(mid).endTime; if(tmpTime > time) { right = mid - 1; }else if (tmpTime == time){ return mid; } else{ left = mid; } } return left; } } class EndStatus{ int endTime;//结束时间 int weight;//权重 List<Integer> item = new ArrayList<>();//任务下标 }