题解 | #单帧操作#

单帧操作

http://www.nowcoder.com/practice/df2ebc45eab84099b843f0bfd8989516

思路:

题目的主要信息:

  • 给一串数组,每次找到一个位置进行一次操作:将该位置前后一个数及本身改为三者中的最大值
  • 一共进行n次操作,每次操作需要找到改变后使数组和最大那个位置来改变

方法一:暴力解法(超时)
具体做法:
利用二进制掩码的特性,枚举所有位置选择或是不选择的组合(相当于n次操作,选择的位置进行排列足组合),按照顺序模拟改变的值,最后更新较大值即可。

class Solution {
public:
    vector<int> solve(int n, vector<int>& a) {
        vector<int> res(n, 0);
        for(int i = 1; i < (1 << n); i++){ //枚举数字的可能性
            int num = 0;
            vector<int> temp = a; //每次记录修改的数组
            for(int j = 0; j < n; j++){
                if((i >> j) & 1){
                    num++;
                    int maxnum = a[j];
                    //处理边界
                    if(j - 1 >= 0)
                        maxnum = max(maxnum, temp[j - 1]);
                    if(j + 1 < n)
                        maxnum = max(maxnum, temp[j + 1]);
                    if(j - 1 >= 0)
                        temp[j - 1] = maxnum;
                    if(j + 1 < n)
                        temp[j + 1] = maxnum;
                    temp[j] = maxnum;
                }
            }
            int sum = 0;
            for(int j = 0; j < n; j++)  //求和
                sum += temp[j];
            res[num - 1] = max(res[num - 1], sum);//更新
        }
        return res;
    }
};

复杂度分析:

  • 时间复杂度:,两个循环,外循环掩码自然是,内循环一次遍历
  • 空间复杂度:,使用辅助数组temp每次回归原来的数组,res属于必要空间

方法二:动态规划
具体做法:
要求的最大值等于数组a的元素和加上每次操作后增加最多的大小。因此我们可以一开始就求出数组a的元素和,然后用辅助数组dp,代表每次操作位置后,处的值为时对应的最大总增量。
我们再借助队列做一个类似bfs的遍历,队列中记录的分别是元素下标、第几次操作、以当前元素为中的连续三个最大值。对于每次操作,从队列中取出元素,向后扩展,更新最大值。
图片说明

我们设置两个dp,其中dp如图所示是记录每次操作后的值,初始时如图所示初始化。而dp1是用来在bfs时找到当前操作的最大增加量,最后需要更新进dp中,dp1的更新方式类似的dp,就不画图了。

class Solution {
public:
    struct S{ 
        int pos, k, mx; //pos是下标,k是第几次操作,mx当前连续三个的最大值
    };
    vector<int> solve(int n, vector<int>& a) {
        vector<int> res(n, INT_MIN);
        int maxe = *max_element(a.begin(), a.end()); //找到最大值
        //dp[i][j]代表每次操作i位置后,i处的值为j时对应的最大总增量
        vector<vector<int> > dp(n + 1, vector<int>(maxe + 1, -1));
        vector<vector<int> > dp1 = dp; //备份在这里供还原dp时使用
        queue<S> q;
        int sum = 0;
        for(int i = 0; i < n; i++){ //处理连续三个数
            sum += a[i];
            int mx = a[i], g = a[i], cnt = 1;
            if(i > 0){ //非下界
                mx = max(a[i - 1], mx);
                g += a[i - 1]; //这三个总值
                cnt++;  //这三个的元素个数,边界处没有三个
            }
            if(i < n - 1){ //非上界
                mx = max(a[i + 1], mx);
                g += a[i + 1];
                cnt++;
            }
            q.push(S{i, 1, mx});  //放入队列中方便bfs
            dp[i][mx] = max(dp[i][mx], cnt * mx - g); //更新增量最大
            res[0] = max(cnt * mx - g, res[0]);
        }
        for(int k = 1; k < n; k++){  //n次操作
            int sz = q.size();
            for(int i = 0; i < sz; i++){ //遍历找到最大增加量
                auto s = q.front();  //出队列
                q.pop();
                int pos = s.pos, kk = s.k, mx = s.mx;
                for(int j = pos + 1; j < n; j++){ //向后扩展mx
                    int mx2, g, cnt = 2;
                    if(j == pos + 1) { //左边
                        mx2 = mx; 
                        g = 2 * mx;
                    }
                    else if(j == pos + 2) {
                        mx2 = max(mx, a[j]);
                        g = mx + a[j];
                    }
                    else {
                        mx2 = max(a[j - 1], a[j]);
                        g = a[j - 1] + a[j];
                    }
                    if(j < n - 1){  //右边
                        mx2 = max(a[j + 1], mx2);
                        g += a[j + 1];
                        cnt++;
                    }
                    if(dp1[j][mx2] == -1) 
                        q.push({j, kk + 1, mx2});//保存状态
                    dp1[j][mx2] = max(dp1[j][mx2], cnt * mx2 - g + dp[pos][mx]);//更新结果
                    res[kk] = max(dp1[j][mx2], res[kk]);
                }
                dp[pos][mx] = -1;//还原数组为-1,方便下一轮扩展用
            }
            swap(dp, dp1);
        }
        for(int i = 0; i < n; i++) 
            res[i] += sum;
        return res;
    }
};

复杂度分析:

  • 时间复杂度:,最坏情况为n次操作,每次相当于遍历dp矩阵
  • 空间复杂度:,最大空间为矩阵的空间
孤帆远影碧空尽 文章被收录于专栏

牛客网各类题单题解~

全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务