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(m∗n2),其中 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的主要内容,如果未能解决你的问题,请参考以下文章