【LeetCode】剑指 Offer Ⅱ 第2章:数组(8道题) -- Java Version

news2024/12/23 4:50:26

题库链接:https://leetcode.cn/problem-list/e8X3pBZi/

数组

题目解决方案
剑指 Offer II 006. 排序数组中两个数字之和双指针(异向) ⭐
剑指 Offer II 007. 数组中和为 0 的三个数排序 + 双指针(异向) ⭐
剑指 Offer II 008. 和大于等于 target 的最短子数组双指针:滑动窗口(同向)⭐
剑指 Offer II 009. 乘积小于 K 的子数组双指针:滑动窗口(同向)⭐
剑指 Offer II 010. 和为 k 的子数组前缀和:哈希表优化 ⭐
剑指 Offer II 011. 0 和 1 个数相同的子数组前缀和:哈希表优化 ⭐
剑指 Offer II 012. 左右两边子数组的和相等前缀和:后缀和的互补 ⭐
剑指 Offer II 013. 二维子矩阵的和二维前缀和 ⭐

使用 双指针 解决子数组之和的面试题有一个前提条件——数组中的所有数字都是正数。如果数组中的数字含有正数、负数和零,那么双指针的思路并不适用,这是因为当数组有负数时,在子数组中添加数字并不一定能增加子数组的和,删除数字也不一定减少。此时,我们就需要使用通解 前缀和 来求解子数组之和,。


1. 剑指 Offer II 006. 排序数组中两个数字之和 – P15

从一个升序数组中,找出两个数满足相加之和等于目标数 target 的下标;

1.2 双指针:首尾指针 – O(n)(⭐)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

class Solution {
    // 1. 双指针
    public int[] twoSum(int[] numbers, int target) {
        int l = 0, r = numbers.length -1;
        while (l < r){
            int sum = numbers[l] + numbers[r];
            if (sum > target) r--;
            else {
                if (numbers[l] + numbers[r] == target) return new int[]{l,r};
                l++;
            } 
        }
        return new int[2];
    }
}

在这里插入图片描述

PS:补充知识1 -【双指针模板】

① 双指针 – O(n)

// i 是 自然遍历到 n的
// 在每个 i 中都会求一下 j, j 代表的是符合当前条件下的位置(j 往左最远能到上什么地方 )
for (int i = 0, j = 0; i < n; i ++ )
{
    while (j < i && check(i, j)) j ++ ;
    // 每道问题的具体逻辑
}
// 常见问题分类:
//   (1) 对于一个序列,用两个指针维护一段区间
//   (2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作

② 模板题

  • AcWing 799. 最长连续不重复子序列
  • AcWing 800. 数组元素的目标和
  • AcWing 2816. 判断子序列

2. 剑指 Offer II 007. 数组中和为 0 的三个数 – P17

给你一个整数数组 nums ,判断是否存在三元组满足 nums[i] + nums[j] + nums[k] == 0,且不重复,返回所有和为 0 且不重复的三元组。

2.1 排序 + 双指针 – O(n2)(⭐)

时间复杂度 O ( n l o g n ) + O ( n 2 ) O(nlogn) + O(n^2) O(nlogn)+O(n2),空间复杂度 O ( 1 ) O(1) O(1)

class Solution {
    // 1. 排序 + 双指针
    public List<List<Integer>> threeSum(int[] nums) {
        int n = nums.length;
        List<List<Integer>> res = new ArrayList<>();

        if (n >= 3) {
            Arrays.sort(nums);  // 对数组排序

            for (int i = 0; i < n-2; ){
                twoSum(nums, i, res);

                while (i < n-1 && nums[i] == nums[++i]);  // 去重:由于是排序数组,所以可以直接判断 nums[i]和nums[i+1]是不是相等的
            }
        }
        return res;
    }

    // 固定一个数,移动两个数,求三数之和是否满足 target
    public void twoSum(int[] nums, int i, List<List<Integer>> res) {
        int j = i + 1, k = nums.length-1;

        while (j < k) {
            int sum = nums[i] + nums[j] + nums[k];
            if (sum == 0) {
                res.add(Arrays.asList(nums[i], nums[j], nums[k]));
                
                while (j < k && nums[j] == nums[++j]);  // 去重
            }
            else if (sum > 0) k--;
            else j++;
        }
    }
}

在这里插入图片描述

PS:补充知识1 - 【快排 & 归并模板】

① 快速排序 – O(nlogn)

// Java Template
public static void quickSort(int q[], int l, int r)
{
    if (l >= r) return;

    int i = l - 1, j = r + 1, x = q[l + r >> 1];
    while (i < j)
    {
        do i ++ ; while (q[i] < x);
        do j -- ; while (q[j] > x);
        if (i < j) swap(q, i, j);
    }
    quickSort(q, l, j);
    quickSort(q, j + 1, r);
}

public static void swap(int[] arr, int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

② 归并排序 – O(nlogn)

// Java Template
public static void mergeSort(int[] q, int[] tmp, int l, int r) {
    if(l >= r) return;
    
    int mid = l + r >> 1;
    mergeSort(q, tmp, l, mid);
    mergeSort(q, tmp, mid+1, r);
    
    int k = 0, i = l, j = mid+1;
    
    while (i <= mid && j <= r) {
        if (q[i] < q[j]) tmp[k++] = q[i++];
        else tmp[k++] = q[j++];
    }
    
    while (i <= mid) tmp[k++] = q[i++];
    while (j <= r) tmp[k++] = q[j++];
    
    for (i = l, j = 0; i <= r; i++, j++) q[i] = tmp[j];
} 

③ 模板题(4道)

  • AcWing 785. 快速排序
  • AcWing 786. 第k个数
  • AcWing 787. 归并排序
  • AcWing 788. 逆序对的数量

3. 剑指 Offer II 008. 和大于等于 target 的最短子数组 – P18

给定一个含有 n 个正整数的数组和一个正整数 target,找出该数组中满足其和 ≥ target 的长度最小的 连续子数组,并返回其长度。

3.1 双指针:滑动窗口 – O(n)(⭐)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

// 1. 双指针:同向 (滑动窗口)
// 更习惯上的写法:
// 动画演示可参考:https://leetcode.cn/problems/2VG8Kg/solution/he-da-yu-deng-yu-target-de-zui-duan-zi-s-ixef/
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length;
        int res = n + 10;  // 一般设置大小,习惯上是真实大小+10
        int sum = 0;  // 记录连续子数组的和
        for (int i = 0, j = 0; i < n; i++) {
            sum += nums[i];  // 每循环一次加一次
            while (sum >= target) {  // 满足条件基本条件后,开始移动j,来缩小范围            
                res = Math.min(res, i-j+1);
                sum -= nums[j++];
            }
        }
        return res == n+10 ? 0 : res;
    }
}

在这里插入图片描述

3.2 前缀和 + 二分 – O(nlogn)

时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn),空间复杂度 O ( 1 ) O(1) O(1)

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length;
        int[] sum = new int[n+10];
        int res = n + 10;

        for (int i = 1; i <= n; i++) sum[i] = sum[i-1] + nums[i-1];  // 习惯上,从 1 开始构建前缀和

        for (int i = 1; i <= n; i++) {
            int d = sum[i] - target;
            int l = 0, r = i;
            while (l < r) {  // 找右端点的二分
                int mid = l + r + 1 >> 1;
                if (d >= sum[mid]) l = mid;  // sum[i] - sum[mid] >= target
                else r = mid-1;
            }
            // System.out.println(l==r); true
            if (d >= sum[r]) res = Math.min(res, i - r);
        }
        return res == n+10 ? 0 : res;
    }
}

在这里插入图片描述

PS:补充知识1 - 【前缀和 & 差分模板】(一维)

① 一维前缀和 S[n] = a[1] + … + a[n]

💡 应用:快速求出一段区域的和(通过一次运算,算出任意一段区间所有数的和),例如 [ l , r ] = S [ r ] − S [ l − 1 ] [l, r] = S[r] - S[l-1] [l,r]=S[r]S[l1];

  • 构建前缀和: S [ i ] = a [ 1 ] + a [ 2 ] + . . . a [ i ] S[i] = a[1] + a[2] + ... a[i] S[i]=a[1]+a[2]+...a[i]
  • 求区分范围: a [ l ] + . . . + a [ r ] = S [ r ] − S [ l − 1 ] a[l] + ... + a[r] = S[r] - S[l - 1] a[l]+...+a[r]=S[r]S[l1]

算法模板:

const int N=100010;
int a[N];
int main(){
    int n,m;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)a[i]=a[i-1]+a[i];
    scanf("%d",&m);
    while(m--){
        int l,r;
        scanf("%d%d",&l,&r);
        printf("%d\n",a[r]-a[l-1]);
    }
    return 0;
}

② 一维差分数组 b[i] = a[i] - a[i-1]

💡 应用:快速帮助我们实现 a 数组在 [l, r] 范围上的统一运算(+c)

  • 让 b[l] + c
  • 让 b[r+1] - c
  • 构建差分: b [ i ] = a [ i ] − a [ i − 1 ] b[i] = a[i] - a[i-1] b[i]=a[i]a[i1];
  • 范围运算: b [ l ] + = c , b [ r + 1 ] − = c b[l] + = c, b[r+1] - = c b[l]+=c,b[r+1]=c
  • 反求前缀和: b [ i ] + = b [ i − 1 ] b[i] += b[i - 1] b[i]+=b[i1]

算法模板:

using namespace std;
int a[100010],s[100010];

int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];   
    for(int i=1;i<=n;i++) s[i]=a[i]-a[i-1];// 读入并计算差分数组
    while(m--){
        int l,r,c;
        cin>>l>>r>>c;
        s[l]+=c;
        s[r+1]-=c;// 在原数组中将区间[l, r]加上c
    }
    for(int i=1;i<=n;i++){
        s[i]+=s[i-1];
        cout<<s[i]<<' ';
    }  // 给差分数组计算前缀和,就求出了原数组
    return 0;
}

③ 模板题(2道)

  • AcWing 795. 前缀和【一维】
  • AcWing 797. 差分【一维】

PS:补充知识2 - 【滑动窗口】

更多内容可参考:
[1] 滑动窗口机制 - CSDN博客
[2] 4.2 TCP 重传、滑动窗口、流量控制、拥塞控制 | 小林coding
[3] 简述滑动窗口的原理 - CSDN博客
[4] 滑动窗口算法基本原理与实践 - huansky - 博客园

① 滑动窗口、流量 & 拥塞控制

💡 滑动窗口(Sliding window)是一种流量控制技术。在早期的网络通信中,通信双方不会考虑网络的拥挤情况直接发送数据。由于大家不知道网络拥塞状况,同时发送数据,可能就会导致中间节点阻塞掉包,谁也发不了数据,所以就有了滑动窗口机制来解决此问题。
……
所谓的流量控制就是动态调节窗口大小发送数据包。发送端第一次以窗口大小(第一次的窗口大小是根据链路带宽的大小来决定的发送数据包,接收端接收这些数据包,并返回确认应答包,告诉发送端自己下次希望收到的数据包是多少(新的窗口大小),发送端收到确认应答包以后,将以该窗口大小进行发送数据包。
……
拥塞控制:虽然TCP有了滑动窗口这个大杀器, 能够高效可靠的发送大量的数据. 但是如果在刚开始阶段就发送大量的数据, 仍然可能引发问题.因为网络上有很多的计算机, 可能当前的网络状态就已经比较拥堵. 在不清楚当前网络状态下, 贸然发送大量的数据, 是很有可能引起雪上加霜的. 于是,TCP引入 慢启动 机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速度传输数据。
其核心如下三点:

  1. 发送开始的时候, 定义拥塞窗口大小为1;
  2. 当发送方每收到一个 ACK,拥塞窗口 cwnd 的大小就会加 1,在未超过慢启动门限 (ssthresh)前,窗口大小将以指数形式增加,超过之后则以线性形式增加;
  3. 当发生超时重传时,窗口大小归0,重新开始计算;当发生快速重传时,窗口大小减半.

……
滑动窗口算法:滑动窗口算法是在给定特定窗口大小的数组或字符串上执行要求的操作,该技术可以将一部分问题中的嵌套循环转变为一个单循环,从而减少时间复杂度。

② 补充题目(3道)

  • 1208. 尽可能使字符串相等 - 力扣(LeetCode)
  • 239. 滑动窗口最大值 - 力扣(LeetCode)
  • 1456. 定长子串中元音的最大数目 - 力扣(LeetCode)

PS:补充知识3 - 【Arrays.binarySearch(sortArray, target)】

更多内容可参考:Arrays.binarySearch 详解 - AllenLeungX的博客

Arrays 类的 binarySearch() 方法,可以使用二分搜索法来搜索指定的数组,以获得指定对象。该方法返回要搜索元素的索引值。但是务必注意:数组必须经过排序后才可以使用此方法,否则返回下标显示不准。(不推荐使用,更推荐手写二分,也不会花费太多时间)

import java.util.Arrays;

public class ArraysBinarySearch {
    public static void main(String[] args) {
        int arr[] = new int[]{3, 5, 7, 9, 11, 13};
        Arrays.sort(arr);
        for (int i = 0; i < 10; i++) {
            System.out.println("数字【" + i + "】:" + Arrays.binarySearch(arr, i));
        }
    }
}

输出:

数字【0】:-1
数字【1】:-1
数字【2】:-1
数字【3】:0
数字【4】:-2
数字【5】:1
数字【6】:-3
数字【7】:2
数字【8】:-4
数字【9】:3

4. 剑指 Offer II 009. 乘积小于 K 的子数组 – P21

给定一个正整数数组 nums和整数 k ,请找出该数组内乘积小于 k 的连续的子数组的个数。

4.1 双指针:滑动窗口 – O(n)(⭐)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

class Solution {
    // 1. 双指针:滑动窗口(同向)
    public int numSubarrayProductLessThanK(int[] nums, int k) {
        int n = nums.length;
        int mul = 1 , cnt = 0;
        for (int r = 0, l = 0; r < n; r++) {
            mul *= nums[r];
            while (mul >= k && l <= r) {
                mul /= nums[l++]; 
            }
            cnt += r >= l ? r-l+1 : 0;  // key: 区间长度就是满足条件新增的区间个数
        }
        return cnt;
    }
}

在这里插入图片描述

5. 剑指 Offer II 010. 和为 k 的子数组 – P22

给定一个整数数组和一个整数 k ,请找到该数组中和为 k 的连续子数组的个数。

通过使用前缀和,我们将这个问题转化为了 p s [ r ] − p s [ l ] = k ; ( l < r ) ps[r] - ps[l] = k; ( l < r ) ps[r]ps[l]=k;(l<r) .

5.1 前缀和:顺序遍历 – O(n2)

时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度 O ( n ) O(n) O(n)

class Solution {
    // 1. 前缀和:顺序遍历
    public int subarraySum(int[] nums, int k) {
        int n = nums.length;
        int[] ps = new int[n + 10];
        int cnt = 0;

        for (int i = 1; i <= n; i++) ps[i] = ps[i-1] + nums[i-1];  // 构建前缀和

        // 然后根据每个前缀和,判断以 i 开头的子数组能否满足条件
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j <= n; j++) {
                if (ps[j] - ps[i] == k) cnt++;
            }
        }
        return cnt;
    }
}

在这里插入图片描述

5.2 前缀和 + 哈希表优化 – O(n)(⭐)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

class Solution {
    // 2. 前缀和:哈希表优化
    public int subarraySum(int[] nums, int k) {
        int n = nums.length;
        int cnt = 0, ps = 0;
        Map<Integer,Integer> map = new HashMap<>();  // key: ps[i], value: 出现次数
        map.put(0,1);  // ps-k == 0,即+1

        for (int num : nums) {
            ps += num;
            cnt += map.getOrDefault(ps-k,0);  // ps[r] - ps[l] = k, cnt++
            map.put(ps, map.getOrDefault(ps, 0) + 1);
        }
        return cnt;
    }
}

在这里插入图片描述

6. 剑指 Offer II 011. 0 和 1 个数相同的子数组 – P24

给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。

可参考:常见子数组问题 通用解法 - 0 和 1 个数相同的子数组 - 力扣(LeetCode)

6.1 前缀和:哈希表优化 – O(n)(⭐)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

class Solution {
    // 1. 前缀和:哈希表优化
    public int findMaxLength(int[] nums) {
        int n = nums.length, len = 0;
        int[] ps = new int[n + 10];
        for (int i = 1; i <= n; i++) ps[i] = ps[i - 1] + (nums[i - 1] == 0 ? -1 : 1);  // 构建前缀和数组
        Map<Integer, Integer> map = new HashMap<>();  // 前缀和,下标
        map.put(0, 0);
        for (int i = 1; i <= n; i++) {
            int t = ps[i];
            if (!map.containsKey(t)) map.put(t, i);
            else len = Math.max(len, i-map.get(t));
        }
        return len;
    }
}

在这里插入图片描述

7. 剑指 Offer II 012. 左右两边子数组的和相等 – P25

给你一个整数数组 nums ,请计算数组的 中心下标,并返回返回 最靠近左边 的那一个 。
中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。

7.1 前缀和 + 后缀和 – O(n)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

class Solution {
    // 1. 1. 前缀和 = 后缀和
    public int pivotIndex(int[] nums) {
        int n = nums.length, res = n+10;
        int[] ps = new int[n+10];
        int[] bs = new int[n+10];
        
        for (int i = 1; i <= n; i++) ps[i] = ps[i-1] + nums[i-1];  // 构建前缀和
        for (int i = n; i >= 1; i--) bs[i] = bs[i+1] + nums[i-1];  // 构建后缀和

        for (int i = 1; i <= n; i++) {
           if (ps[i] == bs[i]) return i-1;  // 找到第一个前缀和与后缀和相等的下标
        }
        return -1;
    }
}

在这里插入图片描述

7.2 前缀和:后缀和的互补 – O(n)(⭐)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

// 还可进一步优化空间复杂度,用一个变量累加来代替前缀和数组在循环中进行计算
class Solution {
    // 2. 前缀和:后缀和的互补 
    public int pivotIndex(int[] nums) {
        int n = nums.length, res = n+10;
        int[] ps = new int[n+10];
        
        for (int i = 1; i <= n; i++) ps[i] = ps[i-1] + nums[i-1];  // 构建前缀和
       
        for (int i = 0; i < n; i++) {
            if (ps[n] == 2 * ps[i] + nums[i]) return i;  // total = 2 * sum + nums[i];
        }
        return -1;
    }
}

在这里插入图片描述

8. 剑指 Offer II 013. 二维子矩阵的和 – P26

给定一个二维矩阵 matrix,计算其子矩形范围内元素的总和,并实现实现 NumMatrix 类;

8.1 二维前缀和(⭐)

时间复杂度 O ( m n ) O(mn) O(mn),空间复杂度 O ( m n ) O(mn) O(mn)

class NumMatrix {
    int[][] ps;
    public NumMatrix(int[][] matrix) {
        int m = matrix.length;
        if (m > 0) {
            int n = matrix[0].length;
            ps = new int[m+10][n+10];

            for (int i = 1; i <= m; i++) 
                for (int j = 1; j <= n; j++)
                    ps[i][j] = ps[i-1][j] + ps[i][j-1] - ps[i-1][j-1] + matrix[i-1][j-1];  // 构建前缀和矩阵
        }
    }
    
    public int sumRegion(int row1, int col1, int row2, int col2) {
        return ps[row2+1][col2+1] - ps[row2+1][col1] - ps[row1][col2+1] + ps[row1][col1];
    }
}

在这里插入图片描述

PS:补充知识1 - 【前缀和 & 差分模板】(二维)

更多内容可参考:【华为机考】专题突破 第二周:前缀和与差分 1109 - TomLazy的博客

① 二维前缀和 S[i, j] = S[i-1,j] + S[i,j-1] - S[i-1,j-1] + a[i,j];

💡 应用

  • 构建前缀和: S [ i , j ] = S [ i − 1 , j ] + S [ i , j − 1 ] − S [ i − 1 , j − 1 ] + a [ i , j ] S[i, j] = S[i-1,j] + S[i,j-1] - S[i-1,j-1] + a[i,j] S[i,j]=S[i1,j]+S[i,j1]S[i1,j1]+a[i,j];
  • 求区间范围: S [ x 2 , y 2 ] − S [ x 1 − 1 , y 2 ] − S [ x 2 , y 1 − 1 ] + S [ x 1 − 1 , y 1 − 1 ] S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1] S[x2,y2]S[x11,y2]S[x2,y11]+S[x11,y11];【以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和】

算法模板:

int s[1010][1010];

int n,m,q;

int main(){
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&s[i][j]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
    while(q--){
        int x1,y1,x2,y2;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        printf("%d\n",s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]);
    }
    return 0;
}

① 二维差分 b[i][j] = a[i][j] - a[i-1][j] - a[i][j - 1] + a[i - 1 ][j - 1];

💡 应用

  • 构建差分数组: b [ i ] [ j ] = a [ i ] [ j ] − a [ i − 1 ] [ j ] − a [ i ] [ j − 1 ] + a [ i − 1 ] [ j − 1 ] b[i][j] = a[i][j] - a[i-1][j] - a[i][j - 1] + a[i - 1 ][j - 1] b[i][j]=a[i][j]a[i1][j]a[i][j1]+a[i1][j1];
  • 反求前缀和: b [ i ] [ j ] + = b [ i − 1 ] [ j ] + b [ i ] [ j − 1 ] − b [ i − 1 ] [ j − 1 ] b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1] b[i][j]+=b[i1][j]+b[i][j1]b[i1][j1];

算法模板:

const int N = 1e3 + 10;
int a[N][N], b[N][N];
void insert(int x1, int y1, int x2, int y2, int c)
{
    b[x1][y1] += c;
    b[x2 + 1][y1] -= c;
    b[x1][y2 + 1] -= c;
    b[x2 + 1][y2 + 1] += c;
}
int main()
{
    int n, m, q;
    cin >> n >> m >> q;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cin >> a[i][j];
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            insert(i, j, i, j, a[i][j]);      //构建差分数组
        }
    }
    while (q--)
    {
        int x1, y1, x2, y2, c;
        cin >> x1 >> y1 >> x2 >> y2 >> c;
        insert(x1, y1, x2, y2, c);//加c
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];  //二维前缀和
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            printf("%d ", b[i][j]);
        }
        printf("\n");
    }
    return 0;
}

③ 模板题(2道)

  • AcWing 796. 子矩阵的和【二维】
  • AcWing 798. 差分矩阵【二维】

9. 继续提升:加练题目

可参考:

  • 双指针 · SharingSource/LogicStack-LeetCode Wiki
  • 滑动窗口 · SharingSource/LogicStack-LeetCode Wiki
  • 前缀和 · SharingSource/LogicStack-LeetCode Wiki
  • 后缀数组 · SharingSource/LogicStack-LeetCode Wiki

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

应用在心率血氧健康监测耳机中的三合一灯珠

随着生活节奏的加快&#xff0c;工作压力的加大&#xff0c;越来越多的人开始注重健身&#xff0c;如此一来&#xff0c;可穿戴健身追踪设备就变得很流行。通过对脉搏血氧测量原理的研究&#xff0c;人们已经发现只要测量出两种波长的透射光在一个完整的脉搏波中光强度的变化量…

面试必考精华版Leetcode328. 奇偶链表

题目&#xff1a; 代码(首刷看解析 day22&#xff09;&#xff1a; class Solution { public:ListNode* oddEvenList(ListNode* head) {if(headnullptr) return nullptr;ListNode* oddhead;ListNode* evenHeadhead->next;;ListNode* evenevenHead;while(even!nullptr&&…

华为OD机试真题 Java 实现【N进制减法】【2023 B卷 200分】,附详细解题思路

目录 专栏导读一、题目描述二、输入描述三、输出描述四、Java算法源码五、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#xff09;》。 …

flask中实现restful-api

flask中实现restful-api 举例&#xff0c;我们可以创建一个用于管理任务&#xff08;Task&#xff09;的API。在这个例子中&#xff0c;我们将有以下API&#xff1a; GET /tasks: 获取所有任务POST /tasks: 创建一个新的任务GET /tasks/<id>: 获取一个任务的详情PUT /t…

加速产品开发周期:PDM系统的设计流程优化

加速产品开发周期&#xff1a;PDM系统的设计流程优化 在现代商业竞争日益激烈的背景下&#xff0c;企业迫切需要加速产品开发周期&#xff0c;快速推向市场&#xff0c;抢占先机。PDM系统&#xff08;Product Data Management&#xff0c;产品数据管理&#xff09;作为一个高效…

Android系统源码 目录结构

前言&#xff1a;Android官方在线看源码地址 https://cs.android.com/ 1.Android系统架构 Android系统架构分为五层&#xff0c;从上到下依次是应用层、应用框架层、系统运行库层、硬件抽象层和Linux内核层。 AOSP 架构 AOSP 的软件堆栈包含以下层&#xff1a; 图 1. AOSP …

【PCB专题】案例:Allegro如何在PCB板上直接修改封装中的特定焊盘

在实际产品设计中我们很可能因为结构、封装的制约而将两个器件放的很近。并且也可能因为是接口器件,所以要求上锡量要多。 但是因为成本的原因我们很可能不会去为了几个器件增加钢网的阶数,以求获得更多的锡量,让PIN脚爬锡更好。而会通过扩大钢网开口的形式来增加锡量。 如…

前端技术基础-css

前端技术基础-css【了解】 一、css理解 概念&#xff1a;CSS&#xff1a;C(cascade) SS(StyleSheet) &#xff0c;级联样式表。作用&#xff1a;对网页提供丰富的视觉效果&#xff0c;进行美化页面(需要在html页面基础上)样式规则&#xff1a;样式1&#xff1a;值1;样式2&…

FPGA学习——电子时钟模拟(新)

文章目录 一、数码管简介二、C4开发板数码管原理图三、代码实现四、实现效果五、总结 博主在之前曾经编写过一篇电子时钟的博客&#xff08;详情请见此篇博文&#xff09;&#xff0c;但曾经编写的电子时钟&#xff0c;未显示小数点位&#xff0c;同时当时的数码管模块是为了电…

增量式PID算法及其MATLAB实现

增量式PID算法是一种常用的控制算法,用于控制系统中的反馈控制。它通过对系统的误差进行递推式的计算,实现对系统输出的调节,使得系统的输出逐渐趋向于设定值。 delta u(k)=u(k)-u(k-1)=Kp*(e(k)-e(k-1))+Ki*e(k)+Kd*(e(k)-2*e(k-1)+e(k-2)) PID算法由三个部分组成:比例(…

如何通过Navicat连接Oracle数据库

本文介绍如何通过Navicat 连接Oracle数据库。以往总是使用Oracle客户端来连接Oracle数据库&#xff0c;但是Oracle客户端一般有几百M的大小&#xff0c;而且安装繁琐配置麻烦。如果可以通过Navicat直接连接Oracle则会非常轻松方便。 1、下载Instant Client Base 用使用Navicat…

【contenteditable属性将元素改为可编辑状态】

元素添加contenteditable属性之后点击即可进入编辑状态 像这种只修改一条属性不必再打开弹框进行编辑&#xff0c;使用contenteditable会很方便 添加失焦、回车、获焦事件 如 <p :contenteditable"item.contenteditable || false"keydown.enter"key($event…

HarmonyOS/OpenHarmony-ArkTS基于API9元服务开发快速入门

一、创建项目 二、创建卡片 三、添加资源 四、具体代码 Entry Component struct WidgetNewCard {/** The title.*/readonly TITLE: string harmonyOs;readonly CONTEXT: string 技术构建万物智联;/** The action type.*/readonly ACTION_TYPE: string router;/** The…

fastadmin列表页 修改 正序排列 倒序排列 desc asc

打开控制器对应的 js文件 &#xff0c;文件目录为 public/assets/js/backend/xxx.js

接口自动化报告,生成本地服务并自动打开时失败

错误原因&#xff1a; 端口号被占用 首先可以在cmd中调出命令窗口然后执行命令netstat -ano就可以查看所有活动的链接&#xff0c;找到被占用的端口号 1、通过命令taskkill /f /t /im "进程名称" &#xff0c;根据进程的名称杀掉所有的进程。或者taskkill /f /t /p…

《码上行动:零基础学会Python编程》书籍分享

Python是一种高级的、面向对象的编程语言&#xff0c;由Guido van Rossum于1991年开发。它具有简洁、易读和可维护的语法&#xff0c;被广泛用于科学计算、Web开发、数据分析、人工智能等领域。 以下是Python的一些特点和优势&#xff1a; 简洁易读&#xff1a;Python采用简洁…

svn工具使用

svn 介绍 解决之道&#xff1a; SCM&#xff1a;软件配置管理 所谓的软件配置管理实际就是对软件源代码进行控制与管理 CVS&#xff1a;元老级产品 VSS&#xff1a;入门级产品 ClearCase&#xff1a;IBM 公司提供技术支持 SVN&#xff1a;主流产品 什么是SVN&#xff…

ATFX汇市:惠誉下调美债评级,白宫债务无序扩张下,美元国际信用受损

环球汇市行情摘要—— 昨日&#xff0c;美元指数上涨0.06%&#xff0c;收盘在101.94点&#xff0c; 欧元贬值0.12%&#xff0c;收盘价1.0984点&#xff1b; 日元贬值0.75%&#xff0c;收盘价143.33点&#xff1b; 英镑贬值0.46%&#xff0c;收盘价1.2776点&#xff1b; 瑞…

【WiFi】Wi-Fi HaLow技术

目录 1.10大Wi-Fi物联网芯片 2.面向物联网的无线通信技术对比 3.Wi-Fi HaLow值得期待 4.选择IoT Wi-Fi芯片和模块时需要考虑哪些因素&#xff1f; 5.Wi-Fi 6 IoT芯片 5.1.乐鑫科技ESP32-C6 5.2.高通Immersive Home 318平台 6.WiFi BLE IoT芯片 6.1.博流智能 BL602/BL…

SQL-事务

set autocommit 0; select * from acount where name 嘉宝 && acount.money > 1000; update acount set money money - 1000 where name 嘉宝; update acount set money money 1000 where name 煎包; commit ; 脏读;当有两个事务使用同一数据库时&#xff0c…