【LeetCode】1465. 切割后面积最大的蛋糕 + 2943. 最大化网格图中正方形空洞的面积 + 2975. 移除栅栏得到的正方形田地的最大面积 +

102 阅读5分钟

1465. 切割后面积最大的蛋糕

题目链接

image.png

image.png

image.png

image.png

Python3

直觉解法

class Solution:
    def maxArea(self, h: int, w: int, horizontalCuts: List[int], verticalCuts: List[int]) -> int:
        h_delta = []
        v_delta = []
        h1 = [0] + horizontalCuts + [h]
        v1 = [0] + verticalCuts + [w]
        h1.sort()
        v1.sort()

        for i in range(1, len(h1)):
            h_delta.append(h1[i]-h1[i-1])

        for i in range(1, len(v1)):
            v_delta.append(v1[i]-v1[i-1])

        return max(h_delta) * max(v_delta) % (10**9 + 7)

看官方题解后 改进

class Solution:
    def maxArea(self, h: int, w: int, horizontalCuts: List[int], verticalCuts: List[int]) -> int:
        h1 = [0] + horizontalCuts + [h]
        v1 = [0] + verticalCuts + [w]
        h1.sort()
        v1.sort()
        
        h_max = 0
        for i in range(1, len(h1)):
            h_max = max(h_max, h1[i]-h1[i-1])
        
        v_max = 0
        for i in range(1, len(v1)):
            v_max = max(v_max, v1[i]-v1[i-1])

        return h_max * v_max % (10**9 + 7)

官方解法: 由于只需要 最大的间隔,所以记录最大值即可

时间复杂度:O(max(nlogn,mlogm))时间复杂度:O(max(n\log n, m\log m)) 数组排序 花销 空间复杂度:O(max(logn,logm))空间复杂度: O(max(\log n, \log m)) 数组排序 花销

class Solution:
    def maxArea(self, h: int, w: int, horizontalCuts: List[int], verticalCuts: List[int]) -> int:
        horizontalCuts.sort()
        verticalCuts.sort()
        return (self.calMaxDelta(horizontalCuts, h) * self.calMaxDelta(verticalCuts, w)) % (10 ** 9 + 7)


    # 子模块: 求最大间隔
    def calMaxDelta(self, lis, boarder):
        res = 0
        pre = 0
        for num in lis:
            res = max(res, num - pre, res)
            pre = num 
        
        return max(res, boarder - pre)

image.png

C++

class Solution {
public:
    int maxArea(int h, int w, vector<int>& horizontalCuts, vector<int>& verticalCuts) {
        int mod = 1e9 + 7;
        sort(horizontalCuts.begin(), horizontalCuts.end());
        sort(verticalCuts.begin(), verticalCuts.end());
        return (long long)calMaxDelta(horizontalCuts, h) * calMaxDelta(verticalCuts, w) % mod;
    }

    // 子模块
    long long calMaxDelta(vector<int> &arr, int boarder){
        int res = 0, pre = 0;
        for (int num : arr){
            res = max(res, num - pre);
            pre = num;
        }
        return max(res, boarder - pre);
    }
};

2943. 最大化网格图中正方形空洞的面积

题目链接

image.png

image.png

image.png

image.png

image.png

Python3

class Solution:
    def maximizeSquareHoleArea(self, n: int, m: int, hBars: List[int], vBars: List[int]) -> int:
        # 只有 Bars 里的 线段 可以 移除   整体是 1*1 网格,要形成更大的空洞,要求 可移除的Bar 应为 连续的。 转为 求解 hBars  和 vBars 里的 最大连续子序列 长度。 同时参考 1465. 切割后面积最大的蛋糕  的贪心思路
        return min(self.calMaxDelta(hBars), self.calMaxDelta(vBars)) ** 2

    # 子模块
    def calMaxDelta(self, Bars):
        mx = 2  # 至少可 移除 一根 , 长度 为 2
        length = 2
        for x, y in pairwise(sorted(Bars)):
            if y - x == 1:  ## 注意 可移除的连续子序列 前后 还有 两格 , 所以之前 置 2
                length += 1
                mx = max(mx, length)  # 有可能会 一直等, 所以 不能放到 else 里
            else:  # 不等了, 重置 length
                length = 2
            
        return mx               
class Solution:
    def maximizeSquareHoleArea(self, n: int, m: int, hBars: List[int], vBars: List[int]) -> int:
        # 只有 Bars 里的 线段 可以 移除   整体是 1*1 网格,要形成更大的空洞,要求 可移除的Bar 应为 连续的。 转为 求解 hBars  和 vBars 里的 最大连续子序列 长度。 同时参考 1465. 切割后面积最大的蛋糕  的贪心思路
        return min(self.calMaxDelta(hBars), self.calMaxDelta(vBars)) ** 2

    # 子模块
    def calMaxDelta(self, Bars):
        mx = 2  # 至少可 移除 一根 , 长度 为 2
        length = 2
        Bars.sort()
        for i in range(1, len(Bars)):
            if Bars[i] - Bars[i-1] == 1:  ## 注意 可移除的连续子序列 前后 还有 两格 , 所以之前 置 2
                length += 1
                mx = max(mx, length)  # 有可能会 一直等, 所以 不能放到 else 里
            else:  # 不等了, 重置 length
                length = 2
            
        return mx               
class Solution:
    def maximizeSquareHoleArea(self, n: int, m: int, hBars: List[int], vBars: List[int]) -> int:
        # 只有 Bars 里的 线段 可以 移除   整体是 1*1 网格,要形成更大的空洞,要求 可移除的Bar 应为 连续的。 转为 求解 hBars  和 vBars 里的 最大连续子序列 长度。 同时参考 1465. 切割后面积最大的蛋糕  的贪心思路
        return min(self.calMaxDelta(hBars), self.calMaxDelta(vBars)) ** 2


    # 子模块
    def calMaxDelta(self, Bars):
        Bars.sort()
        res = 0
        i = 0
        while i < len(Bars):
            loc = i 
            i += 1  ## 

            while i < len(Bars) and  Bars[i] - Bars[i-1] == 1:
                i += 1  #
            
            res = max(res, i - loc + 1)  #  

        return res

不用排序的写法

class Solution:
    def maximizeSquareHoleArea(self, n: int, m: int, hBars: List[int], vBars: List[int]) -> int:
        # 只有 Bars 里的 线段 可以 移除   整体是 1*1 网格,要形成更大的空洞,要求 可移除的Bar 应为 连续的。 转为 求解 hBars  和 vBars 里的 最大连续子序列 长度。 同时参考 1465. 切割后面积最大的蛋糕  的贪心思路
        return min(self.calMaxDelta(hBars), self.calMaxDelta(vBars)) ** 2

    # 子模块
    def calMaxDelta(self, Bars):
        mx = 2 # 记录 最大长度  由于 至少 有一根 可移除的 Bar, 因此 长度至少 为2
        for bar in Bars:
            length = 0
            if bar - 1 in Bars:
                continue

            while bar in Bars:
                length += 1 # 包含了 起始的 一格 
                bar += 1

            mx = max(mx, length + 1)  # 要加上 后面 那一格  

        return mx      

C++

排序后 比较

class Solution {
public:
    int maximizeSquareHoleArea(int n, int m, vector<int>& hBars, vector<int>& vBars) {
        int a = min(calMaxDelta(hBars), calMaxDelta(vBars));
        return a * a;
        
    }

    // 子模块: 求解 最长间隔  最长可删除序列
    int calMaxDelta(vector<int> & Bars){
        int mx = 2;
        int length = 2;
        sort(Bars.begin(), Bars.end());
        for (int i = 1; i < Bars.size(); ++i){
            if (Bars[i] - Bars[i-1] == 1){
                length += 1;
                mx = max(mx, length);
            }
            else{
                length = 2;
            }
        }
        return mx;
    } 
};

不用排序 查找 有时 比排序慢

image.png

class Solution {
public:
    int maximizeSquareHoleArea(int n, int m, vector<int>& hBars, vector<int>& vBars) {
        int a = min(calMaxDelta(hBars), calMaxDelta(vBars));
        return a * a;
        
    }

    // 子模块: 求解 最长间隔  最长可删除序列
    int calMaxDelta(vector<int> & Bars){
        int mx = 2;
        for (int bar : Bars){
            int length = 0;
            if (find(Bars.begin(), Bars.end(),bar-1) == Bars.end())
                continue;

            while (find(Bars.begin(), Bars.end(),bar-1) != Bars.end()){
                length += 1;
                bar += 1;
            }

            mx = max(mx, length + 1);
        }
        return mx;
    } 

};

2975. 移除栅栏得到的正方形田地的最大面积

题目链接

image.png

image.png

image.png

image.png

Python3

class Solution:
    def maximizeSquareArea(self, m: int, n: int, hFences: List[int], vFences: List[int]) -> int:
        hF = [1] + hFences + [m]
        vF = [1] + vFences + [n]
        hF.sort()
        vF.sort()
        sh, sv = set(), set()  # 存储 任意两个 栅栏之间的 间隔
        for i in range(len(hF)):
            for j in range(i+1, len(hF)):
                sh.add(hF[j] - hF[i])

        for i in range(len(vF)):
            for j in range(i+1, len(vF)):
                sv.add(vF[j] - vF[i])

        # s = sh.intersection(sv)  ## 求 边长交集
        # 另一写法
        mx = 0  # 找 最长 边
        for val in sh:
            if val in sv:
                mx = max(mx, val)
                
        if mx == 0:
            return -1  # 无法 形成 正方形

        return mx ** 2 % (10 ** 9 + 7)
class Solution:
    def maximizeSquareArea(self, m: int, n: int, hFences: List[int], vFences: List[int]) -> int:
        hF = [1] + hFences + [m]
        vF = [1] + vFences + [n]
        hF.sort()
        vF.sort()
        sh, sv = set(), set()  # 存储 任意两个 栅栏之间的 间隔
        for i in range(len(hF)):
            for j in range(i+1, len(hF)):
                sh.add(hF[j] - hF[i])

        for i in range(len(vF)):
            for j in range(i+1, len(vF)):
                sv.add(vF[j] - vF[i])

        # s = sh.intersection(sv)  ## 求 边长交集  
        s = sh & sv
        if len(s) == 0:
            return -1  # 无法 形成 正方形

        return max(s) ** 2 % (10 ** 9 + 7)
        

C++

class Solution {
    unordered_set<int> f(vector<int> &a, int mx) {
        a.push_back(1);
        a.push_back(mx);
        sort(a.begin(), a.end());
        unordered_set<int> set;
        for (int i = 0; i < a.size(); i++) {
            for (int j = i + 1; j < a.size(); j++) {
                set.insert(a[j] - a[i]);
            }
        }
        return set;
    }

public:
    int maximizeSquareArea(int m, int n, vector<int> &hFences, vector<int> &vFences) {
        auto h = f(hFences, m);
        auto v = f(vFences, n);
        // if (h.size() > v.size()) {
        //     swap(h, v);
        // }
        int ans = 0;
        for (int x: h) {
            if (v.contains(x)) {
                ans = max(ans, x);
            }
        }
        return ans ? (long long)ans * ans % 1'000'000'007 : -1;
    }
};