LeetCode_Nov_3rd_Week

Posted KuoGavin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode_Nov_3rd_Week相关的知识,希望对你有一定的参考价值。

November 15th : 319. 灯泡开关
November 16th : 391. 完美矩形
November 17th : 318. 最大单词长度乘积


November 15th : 319. 灯泡开关

源自力扣官方题解,完事睡觉!

//version1 brutal force 根据1billion的数据量,暴力解法注定只是图一乐,哈哈
//暴力解法也就是把整个灯泡开闭的过程模拟一遍
class Solution {
public:
    int bulbSwitch(int n) {
        if(n < 2) return n;
        if(n == 2) return 1;
        vector<int> bulbs = vector<int>(n, 1);
        for(int i = n & 0x1 ? 1 : 0; i < n; i+=2) bulbs[i] = 0;
        for(int i = 3; i <= n; i++) 
            for(int j = 0; j < n; j+=i) 
                bulbs[j] = bulbs[j] == 1 ? 0 : 1;
        return accumulate(bulbs.begin(), bulbs.end(), 0);
    }
};
//version2 math method
class Solution {
public:
    int bulbSwitch(int n) {
        //return sqrt(n);
        return sqrt(n+0.5);
    }
};

November 16th : 391. 完美矩形

两种方式,第一种也是比较直观的思路如下:

  • ① 统计小矩形面积,更新左下右上四个值;
  • ② 把每次遍历到的矩形四点坐标放入set中,重复的就去除;
  • ③ 观察set是否只剩4个,且是左下右上四个值的组合;
  • ④ ③满足且小矩形面积之和等于四个值组成矩形面积,返回真否则假。

注意:对于pair,unordered_set 没有专门的哈希函数,若是定义unordered_set<pair<,>>编译器会报错。

class Solution {
public:
    bool isRectangleCover(vector<vector<int>>& rectangles) {
        int sumArea = 0;
        int left = INT_MAX, up = INT_MIN;
        int right = INT_MIN, down = INT_MAX;
        set<pair<int, int>> s;
        for(auto& rectangle : rectangles) {
            left = min(left, rectangle[0]);
            right = max(right, rectangle[2]);
            up = max(up, rectangle[3]);
            down = min(down, rectangle[1]);

            sumArea += (rectangle[2]-rectangle[0]) * (rectangle[3]-rectangle[1]);

            pair<int, int> lu = make_pair(rectangle[0], rectangle[3]);
            if(!s.count(lu)) s.insert(lu); else s.erase(lu);
            pair<int, int> ld = make_pair(rectangle[0], rectangle[1]);
            if(!s.count(ld)) s.insert(ld); else s.erase(ld);
            pair<int, int> ru = make_pair(rectangle[2], rectangle[3]);
            if(!s.count(ru)) s.insert(ru); else s.erase(ru);
            pair<int, int> rd = make_pair(rectangle[2], rectangle[1]);
            if(!s.count(rd)) s.insert(rd); else s.erase(rd);
        }

        pair<int, int> lu = make_pair(left, up);
        pair<int, int> ld = make_pair(left, down);
        pair<int, int> ru = make_pair(right, up);
        pair<int, int> rd = make_pair(right, down);

        if(s.size() == 4 && s.count(lu) && s.count(ld) && s.count(ru) && s.count(rd))
            return sumArea == (up-down)*(right-left);

        return false;
    }
};

第二种思路,是题解当中的,使用堆进行矩阵的边匹配,有些类似拼图的过程,从左至右,从下至上寻找可以拼接的矩阵块,若是最终堆中没有矩阵块的话那么就是完美矩阵,否则就不是。思路可见力扣题解:图解 完美矩形 (扫描线)

class Solution {
public:
    bool isRectangleCover(vector<vector<int>>& rectangles) {
        priority_queue<tuple<int,int,int>, vector<tuple<int,int,int>>, greater<tuple<int,int,int>>> pq;
        // 记录扫描线的堆。扫描线包含矩形的右边界的 x、下边 y 和上边 y
        sort(rectangles.begin(), rectangles.end());//由左往右,自下而上排序
        int i = 0;// i 记录已经扫描的矩形
        int len = rectangles.size();
        int nextX = rectangles[0][0];
        int nextY = INT_MIN;
        // 先将最左边一列的矩形加到堆中,作为匹配的开始
        while(i<len && rectangles[i][0]==nextX){
            // 只有当上一个矩形的上边和下一个矩形的下边相邻时,才符合完美矩形
            if(nextY==INT_MIN || nextY==rectangles[i][1]){
                nextY = rectangles[i][3];
            }else{
                return false;
            }
            // 添加矩形的扫描线,也就是右边界
            tuple<int,int,int> tp = {rectangles[i][2], rectangles[i][1], rectangles[i][3]};
            pq.push(tp);
            i++;
        }
        // 从左到右,从下到上,从已经匹配的矩形开始往右推进,不断进行匹配
        // 因为都是矩形,所以当匹配成功时也一定是矩形
        while(!pq.empty()){
            auto cur = pq.top();
            pq.pop();
            // 从堆顶找一条 x 相同、连续的最长的线段,也就是上下边相接
            int xStart = get<0>(cur);
            int yStart = get<1>(cur);
            int yEnd = get<2>(cur);
            while(!pq.empty() && xStart==get<0>(pq.top()) && yEnd==get<1>(pq.top())){
                yEnd = get<2>(pq.top());
                pq.pop();
            }
            // 从 rectangles[i:] 开始找到与上面线段完美匹配的连续矩形,
            // 也就是和上面线段 x 相接并且高度相等的矩形
            while(i<len && rectangles[i][0]==xStart && rectangles[i][1]==yStart){
                yStart = rectangles[i][3];
                pq.push({rectangles[i][2], rectangles[i][1], rectangles[i][3]});
                i++;
            }
            // 如果没有完美匹配,要么匹配错了,要么已经匹配完了最右的一列
            if(yStart!=yEnd && (i<len || !pq.empty())){
                return false;
            }
        }
        return true;
    }
};

November 17th : 318. 最大单词长度乘积

最开始我觉得 O ( n 2 ) O(n^2) O(n2) 是暴力解以至于花了半个小时去想有什么精妙的能做到 O ( n l o g n ) O(nlogn) O(nlogn) 的解法。于是想着使用位来判定两个字符串是否有重复字母,这样的话,整体的时间复杂度是 O ( n 2 ) + L O(n^2)+L O(n2)+L L L L w o r d s words words 的长度。当然不过不使用位判定的话,时间复杂度就是 O ( m ∗ n 2 ) O(m*n^2) O(mn2),其中 m m m 是单词长度值,时间复杂度更高。当时没注意看数据规模是 1 0 3 10^3 103,想想 O ( n 2 ) O(n^2) O(n2) 的时间复杂度是可以接受的。

class Solution {
public:
    int maxProduct(vector<string>& words) {
        int n = words.size();
        //由于小写字母只有26位,那么使用32位的int做字典即可
        vector<int> dict = vector<int>(n, 0);
        for(int i = 0; i < n; ++i) { //创建每个word的32位整数字典
            for(auto ch : words[i]) {
            	//左移ch-'a'位,将某位赋为1,使用或运算
                dict[i] |= 1 << (int)(ch - 'a');
            }
        }
        int ret = 0, rnd = 0;
        //O(n^2)将word字典两两匹配,如果与结果是0,则满足长度乘积不为0,进行长度乘积的更新
        for(int i = 0; i < n; ++i) { 
            for(int j = i+1; j < n; ++j) {
                rnd = !(dict[i] & dict[j]) ? words[i].size()*words[j].size() : 0;
                ret = max(ret, rnd);
            }
        }           
        return ret;
    }
};

以上是关于LeetCode_Nov_3rd_Week的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode_Dec_3rd_Week

LeetCode_Dec_3rd_Week

LeetCode_Dec_3rd_Week

LeetCode_Nov_4th_Week

LeetCode_Nov_1st_Week

LeetCode_Nov_2nd_Week