LeetCode每日一题:391. 完美矩形【2021/11/15】

365 阅读1分钟

题目链接:391. 完美矩形 - 力扣(LeetCode) (leetcode-cn.com)

难度:Hard

我们把一个矩形的四个角分别命名为 A,B,C,DA,B,C,D

image.png

对于有端点重合的矩形的情况,不可能出现以下 1010 种:

image.png

我们可以维护一个 MapMap,用来存储以某个坐标为端点的矩形的信息。可以把矩形的四个点看作四个方向,则只需要存储坐标上是否有某个方向的矩形就可以。把 AA 记为 0b00010b0001 (整数 11 的二进制表示),把 BB 记为 0b00100b0010,把 CC 记为 0b01000b0100,把 DD 记为 0b10000b1000,如果同时有多个方向的矩形,则进行一次或运算就可以。

比如坐标 (1,3)(1,3) 上有 A,C,DA,C,D 三个方向存在以它为端点的矩形,则 Map[(1,3)]=ACD=0b00010b01000b1000=0b1101Map[(1,3)] = A \mid C \mid D = 0b0001 \mid 0b0100 \mid 0b1000 = 0b1101

这样思路就明确了,我们首先排除端点上存在同方向矩形即 AA,BB,CC,DDAA,BB,CC,DD 的情况,这在输入阶段就可以处理。然后排除 MapMap 中的其他 66 种情况。

需要注意,对于特殊的只有一个方向存在矩形的端点,它一定是大矩形的端点,有且仅有四个。

class Solution {
int dx[4] = {0, 0, 2, 2};
int dy[4] = {1, 3, 3 ,1};
public:
    bool isRectangleCover(vector<vector<int>>& rectangles) {
        map<string,int> m;
        for(auto &rec:rectangles){
            for(int i=0;i<4;i++){
                string tmp = to_string(rec[dx[i]]) + "#" + to_string(rec[dy[i]]);
                if(m[tmp] & (1<<i)){
                    return false;
                } else {
                    m[tmp] |= (1<<i);
                }
            }
        }
        int ver = 0;
        for(auto &p:m){
            int v = p.second;
            if(!(v&(v-1)) && ++ver>4){
                return false;
            }
            if((v&(v-1)) && (v==0b1010 || v==0b0101 || v==0b1110 || v==0b1101 || v==0b1011 || v==0b0111)){
                return false;
            }
        }
        return true;
    }
};