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

devtools/2024/11/19 6:37:58/

目录

  • 一、560.和为K的⼦数组
  • 二、974.和可被K整除的⼦数组
  • 三、525.连续数组
  • 四、1314.矩阵区域和

一、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)表示这种情况。

解题代码:

java">//时间复杂度: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循环,将每一种可能枚举出来。

解题代码:

java">//时间复杂度: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的时候,就是一个符合条件的子数组。

解题代码:

java">//时间复杂度: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 暴力枚举

解题思路:

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

解题代码:

java">//时间复杂度: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 ]

解题代码:

java">//时间复杂度: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的个数,
  • 当个数相同的时候,更新结果。
  • 会超时

解题代码:

java">//时间复杂度: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大于原数组列数,那么就是原数组列数。

解题代码:

java">//时间复杂度: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)的和。

解题代码:

java">//时间复杂度: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;}
}

http://www.ppmy.cn/devtools/135143.html

相关文章

5个有效的华为(HUAWEI)手机数据恢复方法

5个有效的手机数据恢复方法 华为智能手机中的数据丢失比许多人认为的更为普遍。发生这种类型的丢失有多种不同的原因&#xff0c;因此数据恢复软件的重要性。您永远不知道您的智能手机何时会在这方面垮台&#xff1b;因此&#xff0c;预防总比哀叹好&#xff0c;这就是为什么众…

腾讯云单元化架构体系介绍

1.背景 自2018年以来,受“华为、中兴事件”影响,我国科技受制于人的现状对国家稳定和经济发展都提出了严峻考验。目前我国IT架构体系严重依赖国外产品,金融行业尤其明显。大部分传统银行的关键账务系统都架设在IBM的大型机、小型机之上,数据库使用Oracle及DB2,存储采用EM…

使用 Prompt API 与您的对象聊天

tl;dr&#xff1a;GET、PUT、PROMPT。现在&#xff0c;可以使用新的 PromptObject API 仅使用自然语言对存储在 MinIO 上的对象进行总结、交谈和提问。在本文中&#xff0c;我们将探讨这个新 API 的一些用例以及代码示例。 赋予动机&#xff1a; 对象存储和 S3 API 的无处不在…

前端常见的几个包管理工具详解

文章目录 前端常见的几个包管理工具详解一、引言二、包管理工具详解1、npm1.1、npm的安装与使用 2、yarn2.1、yarn的安装与使用 3、pnpm3.1、pnpm的安装与使用 三、步骤二4、包管理工具的选择 四、总结优缺点对比 前端常见的几个包管理工具详解 一、引言 在前端开发的世界里&…

css3的新特性有哪些?

以下是CSS3的一些主要新特性&#xff1a; 盒模型和布局: box-sizing: 允许开发者控制元素的宽度和高度是否包括padding和border。flexbox (弹性盒子布局): 提供了一种更加灵活的方式来布局、对齐和分配容器中项目的空间。grid (网格布局): 用于创建复杂的二维布局&#xff0c;通…

阿里云引领智算集群网络架构的新一轮变革

阿里云引领智算集群网络架构的新一轮变革 云布道师 11 月 8 日~ 10 日在江苏张家港召开的 CCF ChinaNet&#xff08;即中国网络大会&#xff09;上&#xff0c;众多院士、教授和业界技术领袖齐聚一堂&#xff0c;畅谈网络未来的发展方向&#xff0c;聚焦智算集群网络的创新变…

Spring Boot汽车资讯:速度与信息的融合

3系统分析 3.1可行性分析 通过对本汽车资讯网站实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本汽车资讯网站采用SSM框架&#xff0c;JAVA作为开发语言&#…

selinux和防火墙

一、selinux 1、selinux说明 SELinux&#xff08;Security-Enhanced Linux&#xff09;意思是安全强化的linux。主要由美国国家安全局(NSA)开发&#xff0c;开发的目的是为了避免资源的误用。NSA为了控制文件权限与进程的问题&#xff0c;就使用linux来作为研究目标&#xff0…