第207场周赛
第一次参加周赛,只ac出了一道题目,后面还是先加强正确率,再考虑速度。这里记录的代码来自比赛中排名第一,第二的大佬———zqy1018,Heltion
5519. 重新排列单词间的空格(easy)
题目描述:给你一个字符串 text ,该字符串由若干被空格包围的单词组成。每个单词由一个或者多个小写英文字母组成,并且两个单词之间至少存在一个空格。题目测试用例保证 text 至少包含一个单词 。
请你重新排列空格,使每对相邻单词之间的空格数目都 相等 ,并尽可能 最大化 该数目。如果不能重新平均分配所有空格,请 将多余的空格放置在字符串末尾 ,这也意味着返回的字符串应当与原 text 字符串的长度相等。
返回 重新排列空格后的字符串 。
分析:没什么技巧,暴力求解即可,关键是算出空格的个数,分割出单词,这里我采用stringstream处理,简单方便易懂。
class Solution {
public:
string reorderSpaces(string text) {
vector<string> ve;
int blank_count = 0;
blank_count = cal_blank(text);
string buf;
stringstream ss(text);
while(ss>>buf){
ve.push_back(buf);
}
string str = rearranging_fun(ve, blank_count);
if(str.size()==text.size())
cout<<"true"<<endl;
return str;
}
int cal_blank(string text){
int l = text.length();
int n = 0;
for(int i=0;i<text.length();i++){
if(isalpha(text[i]))
n++;
}
return (l-n);
}
string rearranging_fun(vector<string> ve, int blank_count){
string re_str = "";
int str_count = ve.size();
if(ve.size()==1){
re_str += ve[0];
for(int i=0;i<blank_count;i++){
re_str += " ";
}
}
else{
int num = blank_count / (str_count-1);
int num_re = blank_count % (str_count-1);
string blank = "";
for(int i=0;i<num;i++){
blank += " ";
}
string blank_re = "";
for(int i=0;i<num_re;i++){
blank_re += " ";
}
re_str += ve[0];
for(int i=1;i<str_count;i++){
re_str += blank;
re_str += ve[i];
}
re_str += blank_re;
}
return re_str;
}
};
问题:计算需要4ms,步骤太多繁杂。
5520. 拆分字符串使唯一子字符串的数目最大(medium)
题目描述:给你一个字符串 s ,请你拆分该字符串,并返回拆分后唯一子字符串的最大数目。
字符串 s 拆分后可以得到若干 非空子字符串 ,这些子字符串连接后应当能够还原为原字符串。但是拆分出来的每个子字符串都必须是 唯一的 。
注意:子字符串 是字符串中的一个连续字符序列。
分析:DP是用不了的,每一次选择与状态都会与上一次有关系,这里用回溯搜索最好,加上兼职,速度应该是不是太慢的,这里是子集树.
class Solution {
public:
int ans;
int maxUniqueSplit(string s) {
ans=1;
unordered_set<string> has;
dfs(s,0,has);
return ans;
}
void dfs(const string& s,int cur,unordered_set<string>& has){
if(s.size()-cur+has.size()<=ans) return;
if(cur == s.size()){
ans=max(ans,(int)has.size());
}
else{
for(int len=1;cur+len-1<s.size();++len){
string sub=s.substr(cur,len);
if(!has.count(sub)){
has.insert(sub);
dfs(s,cur+len,has);
has.erase(sub);
}
}
}
}
};
添加上的剪枝就是考虑剩余的字符长度加上已经切分好的字符长度,也没有最优值高,后面的就不需要搜索了
5521. 矩阵的最大非负积(medium)
题目描述:给你一个大小为 rows x cols 的矩阵 grid 。最初,你位于左上角 (0, 0) ,每一步,你可以在矩阵中 向右 或 向下 移动。
在从左上角 (0, 0) 开始到右下角 (rows - 1, cols - 1) 结束的所有路径中,找出具有 最大非负积 的路径。路径的积是沿路径访问的单元格中所有整数的乘积。
返回 最大非负积 对 10^9 + 7 取余 的结果。如果最大积为负数,则返回 -1 。
注意,取余是在得到最大积之后执行的。
分析:给定矩阵及其元素,DP求解,使用DP数组,解决重叠子问题;这里有一个注意的地方,就是这里是乘积,元素也有正有负,最大值可以由上一状态的最小值转变而来,也可以由上衣状态的最大值转变而来,所以,在这里要记录每个状态下的最大最小值。边界条件是第一行和第一列。
class Solution {
long long mini[16][16], maxi[16][16];
public:
int maxProductPath(vector<vector<int>>& grid) {
int n = grid.size(), m = grid[0].size();
mini[0][0] = maxi[0][0] = grid[0][0];
for (int i = 1; i < m; ++i)
mini[0][i] = maxi[0][i] = mini[0][i - 1] * grid[0][i];
for (int i = 1; i < n; ++i){
mini[i][0] = maxi[i][0] = mini[i - 1][0] * grid[i][0];
for (int j = 1; j < m; ++j){
mini[i][j] = min(mini[i - 1][j] * grid[i][j], mini[i][j - 1] * grid[i][j]);
mini[i][j] = min(mini[i][j], maxi[i][j - 1] * grid[i][j]);
mini[i][j] = min(mini[i][j], maxi[i - 1][j] * grid[i][j]);
maxi[i][j] = max(maxi[i - 1][j] * grid[i][j], maxi[i][j - 1] * grid[i][j]);
maxi[i][j] = max(maxi[i][j], mini[i][j - 1] * grid[i][j]);
maxi[i][j] = max(maxi[i][j], mini[i - 1][j] * grid[i][j]);
}
}
if (maxi[n - 1][m - 1] < 0) return -1;
return maxi[n - 1][m - 1] % 1000000007ll;
}
};
代码简洁易懂,用空间换时间,可能还不是最优解。
5522. 连通两组点的最小成本
题目描述:给你两组点,其中第一组中有 size1 个点,第二组中有 size2 个点,且 size1 >= size2 。
任意两点间的连接成本 cost 由大小为 size1 x size2 矩阵给出,其中 cost[i][j] 是第一组中的点 i 和第二组中的点 j 的连接成本。如果两个组中的每个点都与另一组中的一个或多个点连接,则称这两组点是连通的。换言之,第一组中的每个点必须至少与第二组中的一个点连接,且第二组中的每个点必须至少与第一组中的一个点连接。
返回连通两组点所需的最小成本。
这题难度有点大,暂时还没有想明白,后续想明白了再补上
constexpr int maxn = 12;
int sum[maxn][1 << maxn], Log[1 << maxn];
int dp[maxn][1 << maxn];
class Solution {
public:
int connectTwoGroups(vector<vector<int>>& cost) {
int n = cost.size();
int m = cost[0].size();
for(int i = 2; i < (1 << 12); i += 1) Log[i] = Log[i >> 1] + 1;
for(int x = 0; x < n; x += 1)
for(int i = 1; i < (1 << m); i += 1)
sum[x][i] = sum[x][i - (i & -i)] + cost[x][Log[i & -i]];
for(int i = 0; i < n; i += 1){
if(i == 0){
for(int j = 0; j < (1 << m); j += 1) dp[i][j] = sum[i][j];
dp[0][0] = 120000;
}
else{
for(int j = 0; j < (1 << m); j += 1){
dp[i][j] = 120000;
for(int k = j; k; k = (k - 1) & j)
dp[i][j] = min(sum[i][k] + dp[i - 1][j ^ k], dp[i][j]);
}
}
for(int j = 0; j < m; j += 1)
for(int k = (1 << m) - 1; k >= 0; k -= 1)
if(k & (1 << j)) dp[i][k ^ (1 << j)] = min(dp[i][k], dp[i][k ^ (1 << j)]);
if(0) for(int k = 0; k < (1 << m); k += 1){
cout << i << " " << k << " " << dp[i][k] << "\n";
}
}
return dp[n - 1][(1 << m) - 1];
}
};
原文地址:https://www.cnblogs.com/wushupei/p/13700670.html
- 【自然框架】之通用权限(九):权限的验证
- 【自然框架】之通用权限(八):权限到字段(列表、表单、查询)
- 【自然框架】之通用权限(七):权限到按钮
- 通过预测API窃取机器学习模型
- 【自然框架】 页面里的父类——把共用的东东都交给父类,让子类专注于其他。
- 血淋林的例子告诉你,为什么防“上传漏洞”要用白名单
- 关于Int自增字段和GUID字段的性能测试。只有测试,没有分析,呵呵
- 【自然框架】 之 资源角色——列表过滤方案(思路篇)
- UVM(七)之phase及objection
- 【自然框架】 之 主从表的添加、修改
- HLS Lesson6-数据类型转换
- 某开源框架从注入到Getshell
- HLS Lesson4-例子
- Docker初探(一)-有关docker的介绍和简单使用
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法