【算法】【优选算法】前缀和(下)

目录

  • 一、560.和为K的⼦数组
    • 1.1 前缀和
    • 1.2 暴力枚举
  • 二、974.和可被K整除的⼦数组
    • 2.1 前缀和
    • 2.2 暴力枚举
  • 三、525.连续数组
    • 3.1 前缀和
    • 3.2 暴力枚举
  • 四、1314.矩阵区域和
    • 4.1 前缀和
    • 4.2 暴力枚举

一、560.和为K的⼦数组

题目链接:560.和为K的⼦数组
题目描述:

题目解析:

  • 求数组中子串的和为k的个数。

1.1 前缀和

解题思路:

  • 假设已经创建好了一个前缀和数组dp,我们使用前缀和的时候,判断从0到 i 位置的和为k的子数组个数,只需要在dp下标[ 0 , i - 1 ]中找dp元素值为dp[ i ] - k的个数即可。
  • 所以我们使用一个容器hash表来存储从0 到 i - 1的前缀和的个数,关键字key就是前缀和,values就是次数。
  • 细节处理:
    • 我们不需要真的使用前缀和数组,只需要遍历原数组时,用一个变量记录遍历过的元素和即可。
    • 当该前缀和就是k的时候,我们上面条件没有考虑,所以我们还要先放入(0,1)表示这种情况。

解题代码:

//时间复杂度:O(n)
//空间复杂度:O(n)
class Solution {
    public int subarraySum(int[] nums, int k) {
        Map<Integer,Integer> hash = new HashMap<>();
        hash.put(0,1);
        int sum = 0;
        int ret = 0;
        for(int i = 0; i < nums.length; i++) {
            sum += nums[i];
            ret += hash.getOrDefault(sum-k,0);
            hash.put(sum, hash.getOrDefault(sum,0)+1);
        }
        return ret;
    }
}

1.2 暴力枚举

解题思路:

  • 直接使用两层for循环,将每一种可能枚举出来。

解题代码:

//时间复杂度:O(n^2)
//空间复杂度:O(1)
class Solution {
    public int subarraySum(int[] nums, int k) {
        int ret = 0;
        for(int i = 0; i < nums.length; i++) {
            int sum = 0;
            for(int j = i; j < nums.length; j++) {
                sum += nums[j];
                if(sum == k) {
                    ret++;
                }
            }
        }
        return ret;
    }
}

二、974.和可被K整除的⼦数组

题目链接:974.和可被K整除的⼦数组
题目描述:

题目解析:

  • 跟上一道题一样的思路,只不过这个是求能被整除的个数而已。

2.1 前缀和

解题思路:

  • 同余定理:如果(a - b)% p == 0 那么a % p 和b % p值相等。
  • Java中负数对正数取余修正:在Java中负数对正数取余余数会是负数,修正方法就是:(a % p + p)% p
  • 使用hash表将i下标前的每一个前缀和与k的余数存入。
  • 再看前面前缀和与当前 前缀和的余数相同的个数即可。
  • 当[0 , i]本身前缀和余数为0的时候,就是一个符合条件的子数组。

解题代码:

//时间复杂度:O(n)
//空间复杂度:O(n)
class Solution {
    public int subarraysDivByK(int[] nums, int k) {
        int ret = 0;
        Map<Integer,Integer> hash = new HashMap<>();
        hash.put(0 % k , 1);
        int sum = 0;
        for(int x : nums) {
            sum += x;
            int key = (sum % k + k ) % k;
            ret += hash.getOrDefault(key,0);
            hash.put(key, hash.getOrDefault(key , 0) + 1);
            
        }
        return ret;
    }
}

2.2 暴力枚举

解题思路:

  • 直接遍历数组,在将遍历元素的和取余即可。
  • 会超时。

解题代码:

//时间复杂度:O(n^2)
//空间复杂度:O(1)
class Solution {
    public int subarraysDivByK(int[] nums, int k) {
        int ret = 0;
        for(int i = 0; i < nums.length; i++) {
            int sum = 0;
            for(int j = i; j < nums.length; j++) {
                sum += nums[j];
                if((sum % k + k) % k == 0) ret++;
            }
        }
        return ret;
    }
}

三、525.连续数组

题目链接:525.连续数组
题目描述:

题目解析:

  • 要我们返回子数组中 0 和1 数量相等的最长子数组的长度。

3.1 前缀和

解题思路:

  • 我们使用一个容器hash表,关键字key来记录原数组每个下标i中的1与0个数差,而values记录这个差值的最小下标。
  • 注意边界情况,如果刚好整个数组满足条件,结果就是数组长 又等于nums.length-1 + 1所以我们初始一个(0,-1)
  • 求长度的时候,我们在前面找到 j 下标与现在 i 下标关键字一样,那么数组区间就是[ j+1 , i ]

解题代码:

//时间复杂度:O(n)
//空间复杂度:O(n)
class Solution {
    public int findMaxLength(int[] nums) {
        int ret = 0;
        int n = nums.length;
        Map<Integer,Integer> hash = new HashMap<>();
        hash.put(0,-1);
        //前面1和0个数之差
        int num = 0;
        for(int i = 0; i < n; i++) {

            if(nums[i] == 0) num--;
            else num++;

            if(hash.containsKey(num)) ret = Math.max(ret, i - hash.get(num));
            else hash.put(num, i);
        }
        return ret;
    }
}

3.2 暴力枚举

解题思路:

  • 两层for循环遍历数组,记录每一个子数组中1和0的个数,
  • 当个数相同的时候,更新结果。
  • 会超时

解题代码:

//时间复杂度:O(n^2)
//空间复杂度:O(1)
class Solution {
    public int findMaxLength(int[] nums) {
        int ret = 0;
        for(int i = 0; i < nums.length; i++) {
            int oneNum = 0;
            int zeroNum = 0;
            for(int j  = i; j < nums.length; j++) {
                if(nums[j] == 0) zeroNum++;
                else oneNum++;

                if(oneNum == zeroNum) ret = Math.max(ret,j-i+1);
            }
        }
        return ret;
    }
}

四、1314.矩阵区域和

题目链接:1314.矩阵区域和
题目描述:

题目解析:

  • 给一个二维数组,给一个k,返回的二维结果数组中数组( i , j )下标的值是原数组( i-k , j-k )到( i+k , j+k)的和。
  • 就像下图中红方框框起来的:

4.1 前缀和

解题思路:

  • 其实着就是前缀和上篇中给出的二维前缀和模版。
  • 我们使用一个二维数组dp比原来数组多一行一列,dp[ i ][ j ]就是原数组中(0 , 0)到(i - 1 , j -1)的元素和。
  • dp[ i ][ j ] = dp[ i - 1][j - 1] + nums[ i - 1][j - 1]。
  • 在结果数组中与原数组大小一样,本来是求原数组( i-k , j-k )到( i+k , j+k)的和。那么对应到dp数组中,都要加1。
  • 注意越界,如果( i-k , j-k )小于0那么就是0,i+k大于原数组行数,那么就是原数组行数,j+k大于原数组列数,那么就是原数组列数。

解题代码:

//时间复杂度:O(n^2)
//空间复杂度:O(n^2)
class Solution {
    public int[][] matrixBlockSum(int[][] mat, int k) {
        int n = mat.length;
        int m = mat[0].length;
        int[][] dp = new int[n+1][m+1];
        dp[0][0] = mat[0][0];
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                    dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + mat[i-1][j-1];
            }    
        } 
        int[][] ret = new int[n][m]; 
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < m; j++) {
                int x2 = i+k > n-1 ? n-1 : i+k;
                int y2 = j+k > m-1 ? m-1 : j+k;
                int x1 = i-k < 0 ? 0 : i-k;
                int y1 = j-k < 0 ? 0 : j-k;
                ret[i][j] = dp[x2+1][y2+1] - dp[x2+1][y1-1+1] - dp[x1-1+1][y2+1]+dp[x1-1+1][y1-1+1];
            }
        }
        return ret;
    }
}

4.2 暴力枚举

解题思路:

  • 先两层for循环,拿到结果数组行列,
  • 再两层for循环,求原数组( i-k , j-k )到( i+k , j+k)的和。

解题代码:

//时间复杂度:O(n^4)
//空间复杂度:O(1)
class Solution {
    public int[][] matrixBlockSum(int[][] mat, int k) {
        int n = mat.length;
        int m = mat[0].length;
        int[][] ret = new int[n][m];
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < m; j++) {
                int x2 = i+k > n-1 ? n-1 : i+k;
                int y2 = j+k > m-1 ? m-1 : j+k;
                int x1 = i-k < 0 ? 0 : i-k;
                int y1 = j-k < 0 ? 0 : j-k;
                for(int w = x1; w <= x2; w++) {
                    for(int q = y1; q <= y2; q++) {
                        ret[i][j] += mat[w][q];
                    }
                }
            }
        }
        return ret;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/918390.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

论文 | Learning to Transfer Prompts for Text Generation

1. 总结与提问 论文摘要总结&#xff1a; 论文提出了一种创新的PTG&#xff08;Prompt Transfer Generation&#xff09;方法&#xff0c;旨在通过迁移提示的方式解决传统预训练语言模型&#xff08;PLM&#xff09;在数据稀缺情况下微调的问题。通过将一组已在源任务中训练好…

TON商城与Telegram App:生态融合与去中心化未来的精彩碰撞

随着区块链技术的快速发展&#xff0c;去中心化应用&#xff08;DApp&#xff09;逐渐成为了数字生态的重要组成部分。而Telegram作为全球领先的即时通讯应用&#xff0c;不仅仅满足于传统的社交功能&#xff0c;更在区块链领域大胆探索&#xff0c;推出了基于其去中心化网络的…

自动驾驶系列—探索自动驾驶数据管理的核心技术与平台

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

【技术解析】Dolphinscheduler实现MapReduce任务的高效管理

MapReduce是一种编程模型&#xff0c;用于处理和生成大数据集&#xff0c;主要用于大规模数据集&#xff08;TB级数据规模&#xff09;的并行运算。本文详细介绍了Dolphinscheduler在MapReduce任务中的应用&#xff0c;包括GenericOptionsParser与args的区别、hadoop jar命令参…

数据结构哈希表-(开放地址法+二次探测法解决哈希冲突)(创建+删除+插入)+(C语言代码)

#include<stdio.h> #include<stdlib.h> #include<stdbool.h> #define M 20 #define NULLDEL -1 #define DELDEY -2typedef struct {int key;int count; }HashTable;//创建和插入 void Insert(HashTable ha[], int m, int p, int key) {int i, HO, HI;HO key…

【android USB 串口通信助手】stm32 源码demo 单片机与手机通信 Android studio 20241118

android 【OTG线】 接 下位机STM32【USB】 通过百度网盘分享的文件&#xff1a;USBToSerialPort.apk 链接&#xff1a;https://pan.baidu.com/s/122McdmBDUxEtYiEKFunFUg?pwd8888 提取码&#xff1a;8888 android 【OTG线】 接 【USB转TTL】 接 【串口(下位机 SMT32等)】 需…

大数据技术Kafka详解 ① | 消息队列(Messages Queue)

目录 1、消息队列的介绍 2、消息队列的应用场景 2.1、应用耦合 2.2、异步处理 2.3、限流削峰 2.4、消息驱动的系统 3、消息队列的两种模式 3.1、点对点模式 3.2、发布/订阅模式 4、常用的消息队列介绍 4.1、RabbitMQ 4.2、ActiveMQ 4.3、RocketMQ 4.4、Kafka 4.…

一家餐饮企业,「闯入」AI阵地

作者| 皮爷 出品|产业家 “我们需要用AI来帮助我们门店破除内卷的状态。”一位连锁餐饮品牌告诉产业家&#xff0c;“这也是我们想尽快把AI用起来的原因&#xff0c;看看能不能带来一些帮助。” 这种情况正发生在一众餐饮企业中。 与这种情况对应的一个背景是&#xff0c…

MySQL的编程语言

一、MySQL基础 使用系统的全局变量@@VERSION查看当前使用的MySQL的版本信息,SQL语句如下: select @@version; 将局部变量varl声明为char的类型,长度值为10,并为其赋值为“程菲” begin declare var1 char(10); set @var1="程菲"; end 通过局部变量查看d_eams数…

【青牛科技】电动工具直流调速专用集成电路GS069,具有电源电压范围宽、功耗小、抗干扰能力强等特性

GS069是芯谷科技推出的一款CMOS工艺、电动工具直流调速专用集成电路。具有电源电压范围宽、功耗小、抗干扰能力强等特点&#xff0c;广泛应用于各种电动工具。 产品基本参数 产品应用 1、应用图&#xff1a; 2、测试参数&#xff1a;&#xff08;VCC9V&#xff0c;RL2K&#…

PyTorch 中使用自动求导计算梯度

使用 PyTorch 进行自动求导和梯度计算 在 PyTorch 中&#xff0c;张量的 requires_grad 属性决定了是否需要计算该张量的梯度。设置为 True 的张量会在计算过程中记录操作&#xff0c;以便在调用 .backward() 方法时自动计算梯度。通过构建计算图&#xff0c;PyTorch 能够有效…

安装pytest失败ModuleNotFoundError: No module named ‘distutils‘

下载一下即可解决 pip install setuptools 下载完成后&#xff0c;再进行下载 pip install pytest

数据结构树和二叉树知识点和递归序列

二叉树知识点 一.树的概念1.1关于树的名词解释 二.二叉树的概念1. 二叉树性质&#xff1a; 三.满二叉树与完全二叉树递归前序遍历递归中序遍历递归后续遍历 一.树的概念 树是一种非线性数据结构&#xff0c;它是由n个或大于n个的结点来组成具有层次关系的一个集合&#xff08;…

【汇编语言】数据处理的两个基本问题(二) —— 解密汇编语言:数据长度与寻址方式的综合应用

文章目录 前言1. 指令要处理的数据有多长&#xff1f;1.1 通过寄存器指明数据的尺寸1.1.1 字操作1.1.2 字节操作 1.2 用操作符X ptr指明内存单元的长度1.2.1 访问字单元1.2.2 访问字节单元1.2.3 为什么要用操作符X ptr指明 1.3 其他方法 2. 寻址方式的综合应用2.1 问题背景&…

【ArcGIS微课1000例】0130:图层组详解与使用

文章目录 一、图层组概述二、创建图层组三、在图层组中管理图层四、对话框中图层组的列表一、图层组概述 图层组包含其他图层。图层组有助于对地图中相关类型的图层进行组织,并且可用于定义高级绘制选项。例如,假设在地图上有两个图层分别用于表示铁路和高速公路。您可将这些…

Cyberchef配合Wireshark提取并解析TCP/FTP流量数据包中的文件

前一篇文章中讲述了如何使用cyberchef提取HTTP/TLS数据包中的文件,详见《Cyberchef配合Wireshark提取并解析HTTP/TLS流量数据包中的文件》,链接这里,本文讲述下如何使用cyberchef提取FTP/TCP数据包中的文件。 FTP 是最为常见的文件传输协议,和HTTP协议不同的是FTP协议传输…

SpringBoot多环境配置的实现

前言 开发过程中必然使用到的多环境案例&#xff0c;通过简单的案例分析多环境配置的实现过程。 一、案例 1.1主配置文件 spring:profiles:active: prod server:port: 80801.2多环境配置文件 开发环境 blog:domain: http://localhost:8080测试环境 blog:domain: https:/…

本草纲目数字化:Spring Boot在中药实验管理中的应用

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理中药实验管理系统的相关信息成为必然。开发…

linux文件与重定向

目录 一、共识原理 二、回顾C语言文件函数 1.fopen 2.fwrite 3.fclose 三、文件系统调用 1.open 2.write 3.访问文件的本质 4.stdin&&stdout&&stderror 5.文件的引用计数 四、重定向 1.文件描述符的分配规则 2. 输出重定向 3.重定向系统调用 4.…

【微服务】SpringBoot 整合ELK使用详解

目录 一、前言 二、为什么需要ELK 三、ELK介绍 3.1 什么是elk 3.2 elk工作原理 四、ELK搭建 4.1 搭建es环境 4.1.1 获取es镜像 4.1.2 启动es容器 4.1.3 配置es参数 4.1.4 重启es容器并访问 4.2 搭建kibana 4.2.1 拉取kibana镜像 4.2.2 启动kibana容器 4.2.3 修改…