第207场周赛

时间:2020-09-20
本文章向大家介绍第207场周赛,主要包括第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