LeetCode 第202场周赛题解报告

5185. 存在连续三个奇数的数组

关键词:循环,判断奇偶
从 i = 2 开始枚举,检查 arr[i-2], arr[i-1], arr[i] 是否均为奇数。

class Solution {
public:
    bool threeConsecutiveOdds(vector<int>& arr) {
        for(int i = 2; i < arr.size(); i++) {
            if(arr[i]%2 == 1 && arr[i-1]%2 == 1 && arr[i-2]%2 == 1) {
                return true;
            }
        }
        return false;
    }
};

5488. 使数组中所有元素相等的最小操作数

关键词:找规律,计数
数组 arr 满足 arr[i] = (2 * i) + 1 ( 0 <= i < n )。
其所有元素的累加和为 ((2*1+1)+(2*n+1))*n/2,化简后为 (n+2)*n。
有累加和可知,操作完成后,每个元素均为 n+2。
操作前,arr 中总共有 x 个元素小于 n+2, x = ⌊ n / 2 ⌋ x = \lfloor n/2 \rfloor x=n/2
这 x 个元素的累加和为 ⌊ n ( n + 4 ) / 4 ⌋ \lfloor n(n+4)/4\rfloor n(n+4)/4
操作后,前 x 个元素的累加和为 ⌊ ( n + 2 ) n / 2 ⌋ \lfloor(n+2)n/2\rfloor (n+2)n/2
因为每次操作,小于 n+2 的元素的累加和会增加一,所以两和作差即为答案, ⌊ ( n 2 ) / 4 ⌋ \lfloor(n^2)/4\rfloor (n2)/4

class Solution {
public:
    int minOperations(int n) {
        return n*n/4;
    }
};

5489. 两球之间的磁力

关键词:二分,贪心
换个题目的描述方式,向 n 个筐中放入m个球,使距离最近的一对球的距离最远。
划重点,一般题目中出现最近最远,最小最大,应该就是在考察二分/三分了。
可用二分算法求解的题目必须具备单调性:如果阈值 x 有解,那么所有小于 x 的阈值均有解。如果阈值 y 没有解,那么所有大约 y 的阈值均没有解。
尝试证明下这道题的单调性:

  • 如果存在一种放置方案,满足任意一对球的距离不小于阈值 x。那么所有小于 x 的阈值,都可以用该方案应对。
  • 如果对于阈值 x,不存在放置方案,那么对于所有大于 x 的阈值,显然都是无法满足的。(比如,一共10个位置,要放3个球,平均占地3.333个位置。你非要球均占地4个,臣妾做不到啊)。

既然满足单调性,直接套上二分模板,然后运用贪心算法,检查是否存在方案满足阈值 mid 即可。

class Solution {
public:
    bool check(const vector<int> &pos, int m, int limit) {
        for(int pre = -limit, i = 0; i < pos.size(); i++) {
            if(pos[i] - pre >= limit) {
                pre = pos[i];
                m -= 1;
                if(m == 0) {
                    return true;
                }
            }
        }
        return false;
    }
    int maxDistance(vector<int>& position, int m) {
        sort(position.begin(), position.end());
        
        int L = 0;
        int R = 1000000000;

        while(L <= R) {
            int mid = (L+R)/2;
            if(check(position, m, mid)) {
                L = mid+1;
            } else {
                R = mid-1;
            }
        }
        return L-1;
    }
};

5490. 吃掉 N 个橘子的最少天数

关键词:DFS,贪心,记忆化
题目中给出了三种策略:

  • 策略一:吃掉一个橘子。
  • 策略二:如果剩余橘子数 n 能被 2 整除,那么你可以吃掉 n/2 个橘子。
  • 策略三:如果剩余橘子数 n 能被 3 整除,那么你可以吃掉 2*(n/3) 个橘子。

最直接的思路就是暴力搜索:
f ( n ) = m i n { f ( n − 1 ) + 1 f ( n / 2 ) + 1 , n % 2 = = 0 f ( n / 3 ) + 1 , n % 3 = = 0 f(n) = min\left\{ \begin{array}{c} f(n-1) + 1 \\ f(n/2) + 1,n\%2 == 0 \\ f(n/3) + 1, n\%3 == 0 \\ \end{array}\right. f(n)=minf(n1)+1f(n/2)+1n%2==0f(n/3)+1n%3==0
但是这样暴力,即使用上记忆化,也要计算 n 个子问题。既然太慢了,那就尝试优化一下。
观察一下上述式子,可以发现是只使用策略一导致了较多的计算量,而且当 N 较大时,只使用策略一显然不是最优解。

  • 只使用策略一需要 N 天。
  • 只使用一次策略二和多次策略一需要 N%2 + 1 + (N%2)/2 天。
    • N%2:先用N%2 次策略一,将 N 变为可被 2 整除。
    • 1 : 使用 1 次策略二。
    • (N%2)/2:还剩这些橘子,继续使用 (N%2) /2 次策略一。
  • 只使用一次策略三和多次策略一需要 N%3 + 1 + N/3天。

显然当 N >= 3 时,后两种组合方案第一种仅使用策略一的方案更优。
后两种组合方案,哪个更优呢?不知道哪个更有鸭,只好都算一下然后取较小值咯,反正计算量也很小了~

总结一下:

当 N <= 2 时,f(n) = n。
当 N > 2 时有:
f ( n ) = m i n { n % 2 + 1 + f ( n / 2 ) n % 3 + 1 + f ( n / 3 ) f(n) = min\left\{ \begin{array}{c} n\%2 + 1 + f(n/2)\\ n\%3 + 1 + f(n/3)\\ \end{array}\right. f(n)=min{n%2+1+f(n/2)n%3+1+f(n/3)

class Solution {
public:
    unordered_map<int, int> mark;
    int f(int n) {
        if(n <= 1) {
            return n;
        }
        auto it = mark.find(n);
        if(it != mark.end()) {
            return it->second;
        }
        return mark[n] = min(f(n/2) + n%2, f(n/3) + n%3) + 1;
    }
    int minDays(int n) {
        return f(n);
    }
};

LeetCode 第202场周赛题解报告_第1张图片

你可能感兴趣的:(力扣周赛)