Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Leetcode 2830. Maximize the Profit as the Salesman #285

Open
Woodyiiiiiii opened this issue Aug 23, 2023 · 0 comments
Open

Leetcode 2830. Maximize the Profit as the Salesman #285

Woodyiiiiiii opened this issue Aug 23, 2023 · 0 comments

Comments

@Woodyiiiiiii
Copy link
Owner

[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];
    }
}

总结

两个方法侧重点不同,但原理都是从满足时间复杂度出发考虑。第一种二分法更适用。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant