《力扣》元素和为目标值的子矩阵数量C++

在这里插入图片描述

//方法一:暴力枚举法
//直接求两个点之间所有数的和
//优点:简单易懂
//缺点:超时

class Solution {
public:
    
struct Point
{
    int x;	//点的横坐标
    int y;	//点的纵坐标
};

int sumMatrix(Point f, Point e, vector<vector<int>> &matrix)
{
	//起点到终点之间所有点求和
    int temp = 0;
    for(int i=f.x;i<= e.x;i++)
    {
        for(int j= f.y;j<= e.y;j++)
        {
            temp += matrix[i][j];
        }
    }
    return temp;
}
int numSubmatrixSumTarget(vector<vector<int>> &matrix, int target)
{
    int res = 0;
    int hang = 0;
    int lie = 0;
    int temp = 0;
    if (matrix.size() != 0)
    {
        hang = matrix.size();	//得到矩阵的行
        if (matrix[0].size() != 0)
        {
            lie = matrix[0].size();	//得到矩阵的列
        }
    }
    
    for (int i = 0; i < hang; i++)
    {
        for (int j = 0; j < lie; j++)
        {
            Point fP; //起点
            fP.x = i;
            fP.y = j;
            for (int k = i; k < hang; k++)
            {
                for (int l = j; l < lie; l++)
                {
                    Point eP; //终点
                    eP.x = k;
                    eP.y = l;
                    temp = sumMatrix(fP, eP, matrix);	//求不规则矩阵的和与target比较
                    if (temp == target)
                    {
                        res++;
                    }
                }
            }
        }
    }
    return res;

}
};

在这里插入图片描述在这里插入图片描述
//有了上述经验后,我想了想,重复计算的值太多,能不能让其中有些值保留下来,为以后用,我观察到当控制起点不动时,终点的推移其实是有顺序的,从当起点先向右走,即每一行先从左到右,每一列从上到下。这便为某些值的重复利用做好铺垫!

//部分优化

class Solution {
    
public:
static int rtemp ;   //起点对应行的右边的值
    static int btemp ;   //起点对应列下边的值
struct Point
{
    int x;
    int y;
};
int sumMatrix(Point f, Point e, vector<vector<int>> &matrix)
{
    int temp=0;
    int hang = e.x;
    int lie = e.y;
    if(f.x == e.x&&f.y == e.y){
        rtemp=matrix[hang][lie];
        btemp=matrix[hang][lie];
        return matrix[hang][lie];
    }
    if (f.x == e.x)
    {
        return rtemp += matrix[hang][lie];
    }
    else if (f.y == e.y)
    {
        return btemp += matrix[hang][lie];
    }
    else
    {
        for (int i = f.x; i <= e.x; i++)
        {
            for (int j = f.y; j <= e.y; j++)
            {
                temp += matrix[i][j];
            }
        }
    }
    return temp;
}
int numSubmatrixSumTarget(vector<vector<int>> &matrix, int target)
{
    int res = 0;
    int hang = 0;
    int lie = 0;
    int temp = 0;
    if (matrix.size() != 0)
    {
        hang = matrix.size();
        if (matrix[0].size() != 0)
        {
            lie = matrix[0].size();
        }
    }
    for (int i = 0; i < hang; i++)
    {
        for (int j = 0; j < lie; j++)
        {
            Point fP; //起点
            fP.x = i;
            fP.y = j;
            for (int k = i; k < hang; k++)
            {
                for (int l = j; l < lie; l++)
                {
                    Point eP; //终点
                    eP.x = k;
                    eP.y = l;
                    temp = sumMatrix(fP, eP, matrix);
                    if (temp == target)
                    {
                        res++;
                    }
                }
            }
        }
        rtemp=0;
        btemp=0;
    }
    return res;
    
}
};

int Solution::rtemp =0;   //起点对应行的右边的值
int Solution::btemp =0;   //起点对应列下边的值

//但是,结果仍然不尽人意!!
这意味着我得重新思考这个问题了!!!
在这里插入图片描述

我注意到:以(0,0)为起点到其它点的数的和总是等于④=②+③-①+x;
④:该点到起点之间的点的和
x:终点处矩阵的值
在这里插入图片描述
此图是tMatrix,比原matrix多一行多一列,便于计算。

class Solution {
    
public:
struct Point
{
    int x;
    int y;
};
int numSubmatrixSumTarget(vector<vector<int>> &matrix, int target)
{
    int res = 0;
    int hang = 0;
    int lie = 0;
    int temp = 0;
    if (matrix.size() != 0)
    {
        hang = matrix.size();
        if (matrix[0].size() != 0)
        {
            lie = matrix[0].size();
        }
    }
    for (int i = 0; i < hang; i++)
    {
        for (int j = 0; j < lie; j++)
        {
            Point f; //起点
            f.x = i;
            f.y = j;
            vector<vector<int>> tMatrix(hang-i+1, vector<int>(lie-j+1, 0));
            for (int k = i; k < hang; k++)
            {
                for (int l = j; l < lie; l++)
                {
                    Point e; //终点
                    e.x = k;
                    e.y = l;
                    int temp=tMatrix[e.x-f.x][e.y+1-f.y]+tMatrix[e.x+1-f.x][e.y-f.y]-tMatrix[e.x-f.x][e.y-f.y]+matrix[e.x][e.y];                    
                    tMatrix[e.x+1-f.x][e.y+1-f.y]=temp;
                    if (temp == target)
                    {
                        res++;
                    }
                }
            }
        }
    }
    return res;
}
};


在这里插入图片描述
//但是还是超时!!!
//我最后想了一种其他的方法

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#define _for(i, a, b) for (int i = a; i < b; i++)
using namespace std;
//打印矩阵,便于验证
// void printMatrix(int hfirst,int flie,int hang, int lie, vector<vector<int>> &m)
// {
//     for (int k = hfirst; k < hang; k++)
//     {
//         for (int l = flie; l < lie; l++)
//         {
//             cout << m[k][l] << " ";
//         }
//         cout << endl;
//     }
// }

int numSubmatrixSumTarget(vector<vector<int>> &matrix, int target)
{

    int res = 0;	//矩阵中任意值等于target的个数
    int hang = 0;	//输入矩阵的行
    int lie = 0;	//输入矩阵的列
    int temp = 0;	//临时判断
	
	/*判断输入矩阵的行和列*/
    if (matrix.size() != 0)
    {
        hang = matrix.size();
        if (matrix[0].size() != 0)
        {
            lie = matrix[0].size();
        }
    }
    // cout << "matrix----------------" << endl;
    // printMatrix(0,0,hang,lie,matrix);
    // cout << "------------------------------------------" << endl;
    
    //tMartix记录起点到终点的和的矩阵
    vector<vector<int>> tMatrix(hang + 1, vector<int>(lie + 1, 0));
    //对tMatrix的复制
    vector<vector<int>> ttMatrix(hang + 1, vector<int>(lie + 1, 0));
    //将矩阵全部清为0
    vector<vector<int>> tttMatrix(hang + 1, vector<int>(lie + 1, 0));
    
    int num = hang * lie;	//矩阵个数
    int i = 0;				//矩阵行的起始坐标
    int j = 0;				//矩阵列的起始坐标
    while (num)
    {
        //cout << "行=" << i << " 列=" << j << endl;        
        if (i == j)		//当起点坐标在对角线上,将其全部清空,因为要重新计算起点到终点的和的矩阵
        {
            tMatrix = tttMatrix;	//清空
            for (int k = i; k < hang; k++)
            {
                for (int l = j; l < lie; l++)
                {
                    temp = tMatrix[k][l + 1] + tMatrix[k + 1][l] - tMatrix[k][l] + matrix[k][l];
                    tMatrix[k + 1][l + 1] = temp;
                    if (temp == target)
                    {
                        res++;
                    }
                }
            }
            //printMatrix(i+1,j+1,hang+1,lie+1,tMatrix);
            ttMatrix = tMatrix;		//复制
            j++; //先水平移动
            if (lie - j <= 0)	//当移动到矩阵最右边时,终点坐标移动到起点坐标的下面
            {
                j = i;
                i++;
            }
        }
        else if (j > i)
        {
            for (int k = i; k < hang; k++)
            {
                for (int l = j; l < lie; l++)
                {
                    temp = tMatrix[k + 1][l + 1] - tMatrix[k + 1][j];
                    tMatrix[k + 1][l + 1] = temp;
                    if (temp == target)
                    {
                        res++;
                    }
                }
            }
            //printMatrix(i+1,j+1,hang+1,lie+1,tMatrix);
            j++;
            if (lie - j <= 0)
            {
                j = i;
                i++;
                tMatrix = ttMatrix;
            }
        }
        else
        {
            for (int k = i; k < hang; k++)
            {
                for (int l = j; l < lie; l++)
                {
                    temp = tMatrix[k + 1][l + 1] - tMatrix[i][l + 1];
                    tMatrix[k + 1][l + 1] = temp;
                    if (temp == target)
                    {
                        res++;
                    }
                }
            }
            //printMatrix(i+1,j+1,hang+1,lie+1,tMatrix);
            i++;
            if (hang - i <= 0)
            {
                j++;
                i = j;
            }
        }
        num--;     
        //cout << "结果等于target的个数=" << res << endl;   
    }
    return res;
}
//
int main()
{
    freopen("D:\\xx.txt", "r", stdin);

    int hang = 5;
    int lie = 5;
    vector<vector<int>> v(hang, vector<int>(lie));
    for (int i = 0; i < hang; i++)
    {
        for (int j = 0; j < lie; j++)
        {
            cin >> v[i][j];
        }
    }
    cout << numSubmatrixSumTarget(v, 0);
    //system("pause");
    return 0;
}

附上xx.txt文件
0 0 0 1 1
1 1 1 0 1
1 1 1 1 0
0 0 0 1 0
0 0 0 1 1
下图红色代表,当i大于j时的情形
在这里插入图片描述
下图蓝色的是j大于i的情况
在这里插入图片描述
整体遍历顺序是
在这里插入图片描述
耗时十多个小时,真的累呀!
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
好的,关于力扣刷题C++常用操作,我可以给你一些常见的操作和技巧: 1. 使用 STL 容器和算法库:STL(Standard Template Library)是 C++ 标准库中的一个重要组成部分,包含了许多常用的容器和算法。在力扣刷题中,使用 STL 可以大大提高代码的效率和可读性。例如,vector 可以用来存储动态数组,sort 可以用来排序等等。 2. 使用 auto 关键字:auto 关键字可以自动推导变量类型,可以减少代码量和提高可读性。例如,auto x = 1; 可以自动推导出 x 的类型为 int。 3. 使用 lambda 表达式:lambda 表达式是 C++11 中引入的一种匿名函数,可以方便地定义一些简单的函数对象。在力扣刷题中,使用 lambda 表达式可以简化代码,例如在 sort 函数中自定义比较函数。 4. 使用位运算:位运算是一种高效的运算方式,在力扣刷题中经常会用到。例如,左移运算符 << 可以用来计算 2 的幂次方,右移运算符 >> 可以用来除以 2 等等。 5. 使用递归:递归是一种常见的算法思想,在力扣刷题中也经常会用到。例如,二叉树的遍历、链表的反转等等。 6. 使用 STL 中的 priority_queue:priority_queue 是 STL 中的一个容器,可以用来实现堆。在力扣刷题中,使用 priority_queue 可以方便地实现一些需要维护最大值或最小值的算法。 7. 使用 STL 中的 unordered_map:unordered_map 是 STL 中的一个容器,可以用来实现哈希表。在力扣刷题中,使用 unordered_map 可以方便地实现一些需要快速查和插入的算法。 8. 使用 STL 中的 string:string 是 STL 中的一个容器,可以用来存储字符串。在力扣刷题中,使用 string 可以方便地处理字符串相关的问题。 9. 注意边界条件:在力扣刷题中,边界条件往往是解决问题的关键。需要仔细分析题目,考虑各种边界情况,避免出现错误。 10. 注意时间复杂度:在力扣刷题中,时间复杂度往往是评判代码优劣的重要指标。需要仔细分析算法的时间复杂度,并尽可能优化代码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

365JHWZGo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值