当前位置:网站首页>LeetCode_Dec_1st_Week
LeetCode_Dec_1st_Week
2022-08-04 05:30:00 【KuoGavin】
December 6th : 1816. 截断句子
December 7th : 1034. 边界着色
December 8th : 689. 三个无重叠子数组的最大和
December 9th : 794. 有效的井字游戏
December 10th : 748. 最短补全词
December 11st : 911. 在线选举
December 12nd : 709. 转换成小写字母
December 6th : 1816. 截断句子
今天我就24周岁啦!承蒙厚爱~ ,得到了人生中的第一个乐高模型,许愿今后能开起不差的B级车吧~!感谢亲爱的!刷个题助助兴 ~
读过题,单词间是固定单个空格的,那么就记录还剩余多少单词没有加上,同时维护窗口,窗口的左右字符都是空格,则说明是一个单词。这样遍历整个输入字符串,然后截取出前k个单词,并拼接成字符串返回即可。
class Solution {
public:
string truncateSentence(string s, int k) {
string ret;
for(int i = 0; i < s.size(); ++i) {
if(s[i] == ' ') continue;
if(k == 0) break; //单词截取完了
int l = i, r = i; //窗口左右边界
while(r < s.size() && s[r] != ' ') r++; //没遇到空格,则扩大窗口
for(int j = i; j < r; ++j) ret += s[j]; //把窗口中单词加到结果字符串上
k--; i = r; //更新剩余单词数,同时更新i的值,以作为新的窗口的初始化值
if(k != 0) ret += " "; //如果不是末尾单词,要加上空格作为分隔符
}
return ret;
}
};
December 7th : 1034. 边界着色
将连通集的边界(网格边界,和不同颜色的边界)染成指定的颜色。就相当于小岛的题,使用 d f s dfs dfs或者 b f s bfs bfs均可。这里使用 d f s dfs dfs,其中如何求得边界是关键,当 d f s dfs dfs到网格边界或者发现相邻格子和初始格子的颜色不一致时,则可判定当前所遍历到的格子是边界格子。再将边界的格子着上指定的颜色即可。
class Solution {
public:
vector<vector<int>> colorBorder(vector<vector<int>>& grid, int row, int col, int color) {
if(row < 0 || row >= grid.size() || col < 0 || col >= grid[0].size()) return grid;
visited = vector<vector<int>>(grid.size(), vector<int>(grid[0].size(), 0)); //初始化访问记录
dfs(grid, visited, row, col, color); //进行dfs
for(int i = 0; i < grid.size(); ++i) //进行边界着色
for(int j = 0; j < grid[0].size(); ++j)
if(visited[i][j] == 2) grid[i][j] = color;
return grid;
}
private:
vector<int> direction = {
-1, 0, 1, 0, -1}; //方向向量
vector<vector<int>> visited; //记录是否访问过,进行dfs剪枝,同时能记录边界
void dfs(vector<vector<int>>& grid, vector<vector<int>>& visited, int row, int col, int color) {
if(row < 0 || row >= grid.size() ||
col < 0 || col >= grid[0].size() || visited[row][col]) return; //如果坐标不合法或已经访问过则返回
visited[row][col] = 1; //标记已经遍历过该坐标
for(int i = 0; i < 4; i++) {
//遍历当前坐标上下左右的四个坐标
int row_new = row + direction[i], col_new = col + direction[i+1];
if(row_new >= 0 && row_new < grid.size() &&
col_new >= 0 && col_new < grid[0].size() &&
grid[row][col] == grid[row_new][col_new]) //如果符合,则说明没有到达连通集边界
dfs(grid, visited, row_new, col_new, color);
else visited[row][col] = 2; //如果不符合,则说明到达连通集边界,将当前坐标标记为2
}
}
};
December 8th : 689. 三个无重叠子数组的最大和
使用三个大小为k的滑动窗口。设 s u m 1 sum_1 sum1为第一个滑动窗口的元素和,该滑动窗口从 [ 0 , k − 1 ] [0,k-1] [0,k−1]开始; s u m 2 sum_2 sum2为第二个滑动窗口的元素和,该滑动窗口从 [ k , 2 k − 1 ] [k,2k-1] [k,2k−1]开始; s u m 3 sum_3 sum3为第三个滑动窗口的元素和,该滑动窗口从 [ 2 k , 3 k − 1 ] [2k,3k-1] [2k,3k−1]开始。
同时向右滑动三个窗口,维护 m a x S u m 12 maxSum_{12} maxSum12(表示第一二窗口的最大和)及对应位置。每次滑动,计算当前的 m a x S u m 12 maxSum_{12} maxSum12与 s u m 3 sum_3 sum3之和。统计过程中 m a x S u m 12 + s u m 3 maxSum_{12}+sum_3 maxSum12+sum3的最大值和各窗口的对应位置。
由于我们是从左向右遍历,当且仅当三个窗口元素和大于的最大值和时才修改元素和,所以更够保证是最小字典序的。
class Solution {
public:
vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {
vector<int> ans;
int sum1 = 0, maxSum1 = 0, maxSum1Idx = 0;
int sum2 = 0, maxSum12 = 0, maxSum12Idx1 = 0, maxSum12Idx2 = 0;
int sum3 = 0, maxTotal = 0;
for (int i = k * 2; i < nums.size(); ++i) {
//将第三个窗口的初始左边界作为i的初始值
//如果没到第三个窗口的初始右边界,则进行窗口中的值的累加
sum1 += nums[i - k * 2];
sum2 += nums[i - k];
sum3 += nums[i];
//当i已经超出第三个窗口的初始右边界时,所有窗口中的值都会发生变化
if (i >= k * 3 - 1) {
if (sum1 > maxSum1) {
//第一个窗口找到了较大和
maxSum1 = sum1; //更新第一个窗口的最大值
maxSum1Idx = i - k * 3 + 1; //更新记录的下标
}
//第二个窗口和和第一个窗口最大和相加大于先前计算的第一二窗口的最大和
if (maxSum1 + sum2 > maxSum12) {
maxSum12 = maxSum1 + sum2; //更新第一二窗口的最大和值
maxSum12Idx1 = maxSum1Idx; //更新此时的第一个窗口的左边界
maxSum12Idx2 = i - k * 2 + 1; //更新此时的第二个窗口的左边界
}
//第一二窗口的最大和和第三个窗口和相加大于之前三个窗口的最大和
if (maxSum12 + sum3 > maxTotal) {
maxTotal = maxSum12 + sum3; //更新三个窗口最大和
ans = {
maxSum12Idx1, maxSum12Idx2, i - k + 1}; //更新左边界坐标
}
//去除旧左边界的值,为接下来的for轮窗口右移做准备
sum1 -= nums[i - k * 3 + 1];
sum2 -= nums[i - k * 2 + 1];
sum3 -= nums[i - k + 1];
}
}
return ans;
}
};
December 9th : 794. 有效的井字游戏
搞清楚怎么才是有效的是解题的关键:
- 首先是X起手,所以X的个数要比O多一个或者是一样多;
- ① 其次,如果X比O多,则不存在O结束游戏的情况(一行/列,或主/副对角线全是O),这样X的个数才可能比O多;
- ② 同理,如果X和O一样多,则说明不存在X结束游戏的情况(一行/列,或主/副对角线全是X)。
理清了只有①②这两种情况才是有效,再将思路编写出代码即可。
class Solution {
public:
bool validTicTacToe(vector<string>& board) {
int cnt = 0, w[128]{
}; //cnt记录XO的差值,O为负
//得到差值,只有两种情况,一是X比O多一个此时cnt==1,二是X和O一样多此时cnt==2
for(auto&& s: board) for(char c: s) cnt += c == 'O' ? -1 : c == 'X';
//扫描各行各列,查找是否有一行或一列都是X或O的情况,
//如果不全是,则不会映射到X或O,即w['X']或w['O']为0
for(int i = 0; i < 3; ++i){
++w[board[i][0] | board[i][1] | board[i][2]];
++w[board[0][i] | board[1][i] | board[2][i]];
}
//扫描主对角线和副对角线
++w[board[0][0] | board[1][1] | board[2][2]];
++w[board[0][2] | board[1][1] | board[2][0]];
//只有两种情况下,才是可能的:
//一是X比O多(cnt==1),且O不存在于一行/列,或主/副对角线(w['O']==0)
//二是X和O一样多(cnt==0),且X不存在于一行/列,或主/副对角线(w['X']==0)
return cnt == 1 && !w['O'] || cnt == 0 && !w['X'];
}
};
December 10th : 748. 最短补全词
把题意弄清楚,然后就是简单的字符串遍历和频次统计的问题了。
class Solution {
public:
string shortestCompletingWord(string licensePlate, vector<string>& words) {
int destIdx = -1; bool flg = true;
int plate[26] = {
0}, word[26] = {
0};
for(int i = 0; i < licensePlate.size(); ++i)
if(isLetter(licensePlate[i])) plate[getIdx(licensePlate[i])]++;
for(int i = 0; i < words.size(); ++i) {
memset(word, 0, 26*sizeof(int));
for(int j = 0; j < words[i].size(); ++j)
if(isLetter(words[i][j])) word[getIdx(words[i][j])]++;
for(int k = 0; k < 26; ++k)
if(plate[k] > word[k]) {
flg = false; break;}
if(flg) {
if(destIdx == -1) destIdx = i;
else destIdx = words[destIdx].size() > words[i].size() ? i : destIdx;
}
flg = true;
}
return words[destIdx];
}
private:
bool isLetter(char ch) {
if(ch <= 'z' && ch >= 'a' || ch <= 'Z' && ch >= 'A') return true;
else return false;
}
int getIdx(char ch) {
if(ch <= 'z' && ch >= 'a') return ch - 'a';
else return ch - 'A';
}
};
December 11st : 911. 在线选举
我在写的时候想复杂了,用的pair数组这个数据结构,其实单独开一个记录票数最高的数组,将初始化的时间数组复用即可。对于查询,根据要查询时间t,找出投票时间中早于t时间的最晚的投票时间(二分查找不大于查询值的右边界的情形,具体见:有序数组二分查找模板:③ 最后的小于等于目标值target的数,即右边界),将该时间的最高得票者返回即可。
//version1
class TopVotedCandidate {
public:
vector<int> tops;
vector<int> times;
TopVotedCandidate(vector<int>& persons, vector<int>& times) {
unordered_map<int, int> voteCounts;
voteCounts[-1] = -1;
int top = -1;
for (auto & p : persons) {
voteCounts[p]++;
if (voteCounts[p] >= voteCounts[top]) {
top = p;
}
tops.emplace_back(top);
}
this->times = times;
}
int q(int t) {
//寻找小于等于t时间的右边界的投票时间
int pos = upper_bound(times.begin(), times.end(), t) - times.begin() - 1;
return tops[pos];
}
};
/** * Your TopVotedCandidate object will be instantiated and called as such: * TopVotedCandidate* obj = new TopVotedCandidate(persons, times); * int param_1 = obj->q(t); */
/**********************************************************************************************************/
//version2
class TopVotedCandidate {
public:
TopVotedCandidate(vector<int>& persons, vector<int>& times) {
int winner = -1, votes = -1;
//record.push_back(make_pair(times[0], persons[0]));
for(int i = 0; i < persons.size(); ++i) {
process[persons[i]]++;
if(votes <= process[persons[i]]) {
winner = persons[i];
votes = process[winner];
};
record.push_back(make_pair(times[i], winner));
}
// for(int i = 0; i < record.size(); ++i)
// cout << "Time:" << record[i].first << " " << "Winner:" << record[i].second << endl;
}
int q(int t) {
cout << ++cnt << " q:";
int l = 0, r = record.size()-1;
while(l <= r) {
int m = (l + r) >> 1;
if(t == record[m].first) return record[m].second;
else if(record[m].first > t) r = m - 1;
else l = m + 1;
}
return record[r].second;
}
private:
unordered_map<int, int> process;
vector<pair<int, int>> record;
};
/** * Your TopVotedCandidate object will be instantiated and called as such: * TopVotedCandidate* obj = new TopVotedCandidate(persons, times); * int param_1 = obj->q(t); */
December 12nd : 709. 转换成小写字母
没什么好讲的,就是大写字母转为小写字母,其余的字符不变即可。这里看评论里有个技巧,提一下,但是因为有其余字符在,所以不适用,但是可以了解一下。
- 大写变小写,小写变大写 : 字符 ^= 32;
- 大写变小写,小写变小写 : 字符 |= 32;
- 小写变大写,大写变大写 : 字符 &= -33;
所有小写字母的 ASCII 码的二进制第六位(从右向左)都是 1 ,而对应的大写字母第六位为 0 ,其他位都一样。 所以转换为小写,只需字符的 ASCII 码的第六位变为 1 ,即与 0b00100000 (32)
做或运算,转换为大写即与0b11011111(-33)
做与运算。
class Solution {
public:
string toLowerCase(string s) {
for(auto& ch : s) {
if(ch <= 'Z' && ch >= 'A')
ch = 'a' + (ch - 'A');
}
// for(int i = 0; i < ret.size(); ++i) {
// if(ret[i] <= 'Z' && ret[i] >= 'A')
// ret[i] = 'a' + (ret[i] - 'A');
// }
//for(auto& ch : s) ch |= 32;
return s;
}
};
边栏推荐
- 度量学习(Metric learning)—— 基于分类损失函数(softmax、交叉熵、cosface、arcface)
- 【Copy攻城狮日志】“一分钟”跑通MindSpore的LeNet模型
- Copy Siege Lions "sticky" to AI couplets
- 强化学习中,Q-Learning与Sarsa的差别有多大?
- 【Copy攻城狮日志】飞浆学院强化学习7日打卡营-学习笔记
- Attention Is All You Need(Transformer)
- 审稿意见回复
- MOOSE平台使用入门攻略——如何运行官方教程的例子
- MNIST Handwritten Digit Recognition - Building a Perceptron from Zero for Two-Classification
- Deep Learning Theory - Initialization, Parameter Adjustment
猜你喜欢
MNIST Handwritten Digit Recognition - Lenet-5's First Commercial Grade Convolutional Neural Network
makefile基础学习
Attention Is All You Need(Transformer)
Copy攻城狮的年度之“战”|回顾2020
MFC读取点云,只能正常显示第一个,显示后面时报错
Thunderbolt turns off automatic updates
深度学习理论 —— 初始化、参数调节
【论文阅读】Anchor-Free Person Search
度量学习(Metric learning、损失函数、triplet、三元组损失、fastreid)
fuser 使用—— YOLOV5内存溢出——kill nvidai-smi 无pid 的 GPU 进程
随机推荐
Thunderbolt turns off automatic updates
Image-Adaptive YOLO for Object Detection in Adverse Weather Conditions
MAE 论文《Masked Autoencoders Are Scalable Vision Learners》
ValueError: Expected 96 from C header, got 88 from PyObject
"A minute" Copy siege lion log 】 【 run MindSpore LeNet model
MNIST Handwritten Digit Recognition - Building a Perceptron from Zero for Two-Classification
Pytorch语义分割理解
TypeError: load() missing 1 required positional argument: ‘Loader‘
Deep Learning Theory - Initialization, Parameter Adjustment
MNIST手写数字识别 —— ResNet-经典卷积神经网络
计算某像素点法线
No matching function for call to 'RCTBridgeModuleNameForClass'
pytorch学习-没掌握的点
YOLOV4流程图(方便理解)
The Unity of ML - agents interpret parameter Settings
浅谈游戏音效测试点
如何成长为高级工程师?
The second official example analysis of the MOOSE platform - about creating a Kernel and solving the convection-diffusion equation
详解近端策略优化
【论文阅读】Multi-View Spectral Clustering with Optimal Neighborhood Laplacian Matrix