Leetcode 1665 Minimum Initial Energy to Finish Tasks

这道题的输入是数组,解题方法不像DP,不像math,又要有顺序,那我就觉得是一道贪心的题,然后看了他给的例子,后面两个例子都是乱排的,换个顺序也可以。所以到底是贪什么呢?(贪心的题目都是要排序的)

贪的不是消耗值(actual), 不是启动值(minimum), 就让人想到了“性价比”。每组只有两个数,加减乘除看下来,相减似乎是个合适的选项。那么先按照启动值 - 消耗值的大小排序看看。

其实到这里,你离解开这道题就不远了。刷LeetCode就像刷高考题一样,题型就那几个,看清了题型,套路就完事了。但是写日记,不能暴露我总是靠蒙来做题这个事实[斜眼笑]。

动动脑子理解一下这道题,可以这样想:工厂里有一堆箱子,每个箱子有其静摩擦力和滑动摩擦力,现在要将这些箱子排成一排推走,求最省力的方法。想要省力,要把“最能传递力”的箱子放到前面,即[静摩擦力 减去 滑动摩擦力]最大的放到前面,这样推箱子的过程中,相对来说最需要力却不怎么消耗力的放在前面,就能传递更多的力给后面的箱子,这样最省力。最后一个箱子需要其静摩擦力大小的力来启动,从最后一个箱子分析,倒推回第一个箱子,就知道总共需要多少力了。

倒推公式:前一个箱子所需要的力,是它[需要传递给后面箱子的力 加上 它本身消耗的滑动摩擦力],与其[静摩擦力]的最大值。这样看,这道题又有动态规划的思想:通过当前状态推断出下一个状态。时间复杂度与空间复杂度就是排序的复杂度。

static int x = [] () {ios::sync_with_stdio(false); cin.tie(0); return 0;} ();
class Solution {
 public:
  int minimumEffort(vector<vector<int>>& tasks) {
    sort(tasks.begin(), tasks.end(), [&] (const auto &a, const auto &b) {
      return (a[1] - a[0]) > (b[1] - b[0]);
    });
    int res = tasks.back()[1];
    for (int i = tasks.size() - 2; i >= 0; --i)
      res = max(res + tasks[i][0], tasks[i][1]);
    return res;
  }
};

#直达链接

LeetCode 1665. Minimum Initial Energy to Finish Tasks