Leetcode 2830. Maximize the Profit as the Salesman
Woodyiiiiiii opened this issue · comments
[2830. Maximize the Profit as the Salesman
2830. Maximize the Profit as the Salesman
类似题目:
2008. Maximum Earnings From Taxi
二分法方法题单(不同的是值域范围很大):
2054. Two Best Non-Overlapping Events / 1235. Maximum Profit in Job Scheduling
一、二分法
一看到题目我就知道要用选或不选DP,但是因为有两个范围,很容易达到范围相乘的效果造成超时。那么问题关键是遍历一个变量,对另一个变量模糊处理。竞赛中我理所当然地把能购买的房子变量当作主遍历变量,对值域进行模糊处理了。模糊处理的方法是用二分法,如果选择卖了该房子,那么就跳跃到该房子卖后所能选择的最近的卖房值域起点。
跟No.2054/No.1235一样的思路,在值域范围很大的情况下优先使用。
class Solution {
List<List<Integer>> offers;
int n;
int offerSize;
int[] dp;
TreeMap<Integer, Integer> treeMap;
public int maximizeTheProfit(int n, List<List<Integer>> offers) {
offers.sort((o1, o2) -> {
if (o1.get(0).equals(o2.get(0)))
return o1.get(1).compareTo(o2.get(1));
return o1.get(0).compareTo(o2.get(0));
});
this.offers = offers;
this.n = n;
this.offerSize = offers.size();
this.dp = new int[offerSize];
Arrays.fill(dp, -1);
treeMap = new TreeMap<>();
for (int i = 0; i < offerSize; i++) {
int start = offers.get(i).get(0);
if (!treeMap.containsKey(start)) {
treeMap.put(start, i);
}
}
treeMap.put(n, offerSize);
return dfs(0);
}
private int dfs(int i) {
if (i >= offerSize) {
return 0;
}
if (dp[i] != -1) {
return dp[i];
}
int max = dfs(i + 1);
List<Integer> offer = offers.get(i);
int end = offer.get(1), gold = offer.get(2);
Integer next = treeMap.ceilingKey(end + 1);
if (next != null) {
int j = treeMap.get(next);
max = Math.max(max, dfs(j) + gold);
}
return dp[i] = max;
}
}
值域
该方法注重值域,适用于值域没有超过极限的情况下。对值域遍历,每次遍历该点所能选择后的房子范围。dp[i]表示[0,i]之间的最大利润。时间复杂度是O(n + m)。
类似题目是No.2008。
class Solution {
public int maximizeTheProfit(int n, List<List<Integer>> offers) {
Map<Integer, Set<int[]>> map = new HashMap<>();
for (List<Integer> offer : offers) {
int start = offer.get(0), end = offer.get(1), profit = offer.get(2);
map.putIfAbsent(end, new HashSet<>());
map.get(end).add(new int[]{start, profit});
}
int[] dp = new int[n + 1];
for (int i = 0; i < n; i++) {
dp[i + 1] = dp[i];
for (int[] offer : map.getOrDefault(i, new HashSet<>())) {
dp[i + 1] = Math.max(dp[i + 1], dp[offer[0]] + offer[1]);
}
}
return dp[n];
}
}
总结
两个方法侧重点不同,但原理都是从满足时间复杂度出发考虑。第一种二分法更适用。