391. Perfect Rectangle

本文介绍了一种算法,用于判断一组矩形是否能够精确覆盖一个更大的矩形区域,包括了具体的实现思路与代码示例。
Given N axis-aligned rectangles where N > 0, determine if they all together form an exact cover of a rectangular region.

Each rectangle is represented as a bottom-left point and a top-right point. For example, a unit square is represented as [1,1,2,2]. (coordinate of bottom-left point is (1, 1) and top-right point is (2, 2)).


Example 1:

rectangles = [
  [1,1,3,3],
  [3,1,4,2],
  [3,2,4,4],
  [1,3,2,4],
  [2,3,3,4]
]

Return true. All 5 rectangles together form an exact cover of a rectangular region.

Example 2:

rectangles = [
  [1,1,2,3],
  [1,3,2,4],
  [3,1,4,2],
  [3,2,4,4]
]

Return false. Because there is a gap between the two rectangular regions.

具体题目见leetcode原题, 这题是leetcode周赛第二次的压轴题。首先自己得知道怎么判断是否是刚好覆盖矩形区域。也就是算法层面的判断准则。
1. 矩形轮廓的要求:有且仅有四个单一的点存在,也就是其他的点至少有两次;
2. 没有重叠的要求:每个点不能同时充当多个矩形的同一位置点,也就是不能同时是俩矩形的左下角或者左上角之类的。
3. 总要求:每次累加小矩形面积,最后计算大矩形面积,必须相等,这样就没有重叠没有间隔。

鉴于上面的规则,我们可以遍历一遍数组,然后我们需要统计,点的坐标系位置(x, y),点的矩形功能位置(左右上下),以及出现次数。这里可以有的基本做法是,建立一个:

unordered_map<int, unordered_map<int, int>> m;
m[x][y]++;

这样就可以统计每一组坐标出现的次数,最后检验出现次数为1的是否只有四个。
对于位置判断,可以用1,2,3,4表示四个角的位置,只要每一组坐标不要在同一个位置有重复就可以。

unordered_map<int, unordered_map<int, vector<int>>> m;
m[x][y].push_back(1.2.3.4?);

遍历的时候,将出现过的坐标添加进最后的vector, 同时判断加的新位置出现过没,一旦出现返回错误。
上述思想用数据结构实现的比较繁琐,这里就体现了大神做法的高明,在表示种类区分这种事上,二进制中1的位置一直是一个很好的做法,我们可以用1(0001),2(0010),4(0100),8(1000)表示四个角,然后如果对每个坐标伴随着新矩形位置进行检索的时候,做位与运算,如果结果不为0,那么证明位置有重叠,返回错误,如果没有重叠就做位或运算,添加一个新出现的位置。这样就解决了最为麻烦的条件2,条件1就直接数最后1,2,4,8的个数是不是4个就行。同时面积的问题只要累加每个小面积同时检索的时候记录最小最大的x,y坐标就行。代码如下:

bool isRectangleCover(vector<vector<int>>& rectangles) {
    unordered_map<string, int> m;
    int minx = INT_MAX, miny = INT_MAX, maxx = INT_MIN, maxy = INT_MIN;
    int area = 0;
    for (auto & rect: rectangles) {
        // 统计四个Corner的值
        minx = min(minx, rect[0]);
        miny = min(miny, rect[1]);
        maxx = max(maxx, rect[2]);
        maxy = max(maxy, rect[3]);
        // 逐一计算面积累加
        area += (rect[2] - rect[0]) * (rect[3] - rect[1]);
        // 判断是否有overlap
        if (!isValid(m, to_string(rect[0]) + "_" + to_string(rect[1]), 1)) return false; // bottom-left
        if (!isValid(m, to_string(rect[0]) + "_" + to_string(rect[3]), 2)) return false; // top-left
        if (!isValid(m, to_string(rect[2]) + "_" + to_string(rect[3]), 4)) return false; // top-right
        if (!isValid(m, to_string(rect[2]) + "_" + to_string(rect[1]), 8)) return false; // bottom-right
    }
    int cnt = 0;
    for (auto it = m.begin(); it != m.end(); ++it) {
        int t = it->second;
        if (t != 15 && t != 12 && t != 10 && t != 9 && t != 6 && t != 5 && t!= 3) {
            ++cnt;
        }
    }
    if ((cnt == 4) && (maxx - minx) * (maxy - miny) == area) return true;
    else return false;
}
bool isValid(unordered_map<string, int>& m, string corner, int type) {
    int& val = m[corner];
    if (val & type) return false;
    val |= type;
    return true;
}

后来发现,其实只要1,3两个条件就能满足所有情况,这个我并不知道怎么证明,但确实也没找到反例,leetcode也是通过没问题。这样一来代码也简化了很多。

bool isRectangleCover(vector<vector<int>>& rectangles) {
    unordered_map<int,unordered_map<int, int>> m;
    int minx = INT_MAX, miny = INT_MAX, maxx = INT_MIN, maxy = INT_MIN;
    int area = 0;
    for (auto& rect: rectangles) {
        // 统计四个Corner的值
        minx = min(minx, rect[0]);
        miny = min(miny, rect[1]);
        maxx = max(maxx, rect[2]);
        maxy = max(maxy, rect[3]);
        // 逐一计算面积累加
        area += (rect[2] - rect[0]) * (rect[3] - rect[1]);
        // 判断是否有overlap
        m[rect[0]][rect[1]]++;
        m[rect[0]][rect[3]]++;
        m[rect[2]][rect[1]]++;
        m[rect[2]][rect[3]]++;
    }
    for (auto& itx: m) {
        int x = itx.first;
        for (auto& ity: itx.second) {
            int y = ity.first;
            int count = ity.second;
            if ((x == minx || x == maxx) && (y == miny || y == maxy)) {
                if (count != 1) return false;
            }
            else {
                if (count != 2 && count != 4) {
                    return false;
                }
            }
        }
    }
    return area == (maxx-minx)*(maxy-miny);
}
Implement the classic method for composing secret messages called a square code. Given an English text, output the encoded version of that text. First, the input is normalized: the spaces and punctuation are removed from the English text and the message is down-cased. Then, the normalized characters are broken into rows. These rows can be regarded as forming a rectangle when printed with intervening newlines. For example, the sentence ```text "If man was meant to stay on the ground, god would have given us roots." ``` is normalized to: ```text "ifmanwasmeanttostayonthegroundgodwouldhavegivenusroots" ``` The plaintext should be organized into a rectangle as square as possible. The size of the rectangle should be decided by the length of the message. If `c` is the number of columns and `r` is the number of rows, then for the rectangle `r` x `c` find the smallest possible integer `c` such that: - `r * c >= length of message`, - and `c >= r`, - and `c - r <= 1`. Our normalized text is 54 characters long, dictating a rectangle with `c = 8` and `r = 7`: ```text "ifmanwas" "meanttos" "tayonthe" "groundgo" "dwouldha" "vegivenu" "sroots " ``` The coded message is obtained by reading down the columns going left to right. The message above is coded as: ```text "imtgdvsfearwermayoogoanouuiontnnlvtwttddesaohghnsseoau" ``` Output the encoded text in chunks that fill perfect rectangles `(r X c)`, with `c` chunks of `r` length, separated by spaces. For phrases that are `n` characters short of the perfect rectangle, pad each of the last `n` chunks with a single trailing space. ```text "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau " ``` 上述为题目要求,请用C语言实现,函数声明如下: char *ciphertext(const char *input)
最新发布
08-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值