小美的平衡矩阵(前缀和例题 — 美团笔试编程题)

        2024美团春招,被这一题给难住了 美团校招笔试真题_Java工程师、C++工程师_牛客网

题目:

        

        

解答:

        这道题的关键点就是要计算出以某一点为矩阵右下角时,1的个数

        我一开始是想着遍历,以某一点为起点(矩阵左上角),遍历i*i的矩阵,但是要用五层循环,超时了。然后又想着将之前的矩阵的结果保留下来,这样计算新矩阵时就能大大减少遍历次数,只用查看前面矩阵的结果来推算出当前矩阵的结果,可是我用的是动态规划,会计算左边和上边的值,这有一个问题,就是左上角对角线位置的值会被计算两次,因为上边的左边算了一次,左边的上边也算了一次。后来看了别人的代码,发现只要动态规划时只计算一边,即上边或者左边的值,另一个值在本次循环的时候单独计算就能解决了,这就是前缀和,用于在数组或矩阵中快速计算某个区间内的元素和。

        这道题的思路就是,用前缀和计算出从左上角[0,0]到右下角[x,y]这个范围内的矩阵的值,这样,如果想要计算以[x,y]为终点的 i*i 的矩阵的值,就只需要用[x,y]的值减去[x-i,y]和[x,y-1]的值再加上以[x-i,y]为终点、以[x,y-1]为终点这两个矩阵的重合部分(刚刚被减了两次)就行了。

        之后再对结果进行判断,就能知道以[x,y]为终点的 i*i 的矩阵是否是平衡矩阵。如果是则记录。

        这种方法只有三层循环,大大降低了时间复杂度。

int main() {
    int n = 4;
    vector<string> matrix(n);
    matrix[0] = "1010";
    matrix[1] = "0101";
    matrix[2] = "1100";
    matrix[3] = "0011";


    vector<vector<int>> dp(n + 1, vector<int>(n + 1));

    for (int i = 0; i < n; i++) {
        int sum = 0;
        //动态规划,但是如果又加上面又加左边会导致对角线左上方被算两次,所以只动态规划算上面,左边的单独在本趟算
        for (int j = 0; j < n; j++) {
            if (matrix[i][j] == '1') sum++;
            dp[i + 1][j + 1] = sum + dp[i][j + 1];
        }
    }


    vector<int> res(n + 1);

    //i*i的矩阵
    for (int i = 1; i <= n; i++) {
        //当矩阵内元素个数为奇数,一定不平衡
        //一个奇数的平方一定是奇数
        if (i % 2 != 0) {
            res[i] = 0;
            continue;
        }
        //以[x,y]为起点的矩阵,其右下角值=以其右下角为终点的矩阵的1的个数
        //x+i-1 -- i为2时,计算x和x+1位置,那么包括x位置在内,总共i个位置需要合法,也就是接下来的i-1个位置需要合法
        for (int x = 1; x + i - 1 <= n; x++) {
            for (int y = 1; y + i - 1 <= n; y++) {
                //[x+i-1][y+i-1]的值是从[1,1]到[x+i-1][y+i-1]的值
                //  那么如果要计算以[x+i-1][y+i-1]为终点的i*i矩阵1的值,需要减去以[x+i-1][y-1]为终点的矩阵2的值和以[x-1][y+i-1]为终点的矩阵3的值
                //  这还不够,矩阵2和矩阵3有一个重合的区域,如果只是减的话,重合的区域会被减两次,所以减完后还需要加上一个重合的区域的值,也就是以[x-1][y-1]为终点的矩阵4的值
                int val = dp[x + i - 1][y + i - 1] - dp[x + i - 1][y - 1] - dp[x - 1][y + i - 1] + dp[x - 1][y - 1];
                if (val == (i * i) / 2) {
                    res[i]++;
                }
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        cout << res[i] << endl;
    }


    return 0;
}

版权声明:本文为博主作者:Eclips3原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/weixin_44343938/article/details/137128412

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2024年4月22日
下一篇 2024年4月22日

相关推荐