博客 / 詳情

返回

leetcode——數組算法——前綴和構建和應用

leetcode——數組算法——前綴和構建和應用

前綴和技巧適用於快速、頻繁地計算一個索引區間內的元素之和

303. 區域和檢索 - 數組不可變

比如leetcode 303. 區域和(檢索 - 數組不可變)

題目介紹:

給定一個整數數組 nums,處理以下類型的多個查詢:

  1. 計算索引 leftright (包含 leftright)之間的 nums 元素的 ,其中 left <= right

實現 NumArray 類:

  • NumArray(int[] nums) 使用數組 nums 初始化對象
  • int sumRange(int i, int j) 返回數組 nums 中索引 leftright 之間的元素的 總和 ,包含 leftright 兩點(也就是 nums[left] + nums[left + 1] + ... + nums[right] )

示例 1:

輸入:
["NumArray", "sumRange", "sumRange", "sumRange"]
[[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]
輸出:
[null, 1, -1, -3]

解釋:
NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]);
numArray.sumRange(0, 2); // return 1 ((-2) + 0 + 3)
numArray.sumRange(2, 5); // return -1 (3 + (-5) + 2 + (-1)) 
numArray.sumRange(0, 5); // return -3 ((-2) + 0 + 3 + (-5) + 2 + (-1))

解法一:

1.在sumRange裏面,for循環從left到right遍歷nums,用一個變量記錄。

代碼如下:

class NumArray {
    //類裏肯定有一個int[]成員
    private int[] myArray;
    public NumArray(int[] nums) {
        this.myArray=nums;
    }
    
    public int sumRange(int left, int right) {
        int result=0;
        if(left>right||left<0||right>myArray.length){
            return 0;
        }
        //myArray[left]一直加到myArray[right]
        for(int i=left;i<=right;i++){
            result+=myArray[i];
        }
        return result;
    }
}
如果多次調用sumRange,會一直重複計算。

解法2

2.在構造函數中,構造一個關於nums的前綴和數組preNums,preNums[i]的值就是nums前i項的和。

Q:如何構造這個前綴和數組?

A:前綴和數組的每一項 = 前一項(前i-1項的和)+ nums[i]。

注意:因為前綴和數組的表達意義應該是前1項的和,前2項的和;而沒有個前0項的和。

所以這裏將preNum[0]=0;目的是更符合我們的表達語義。

比如preNum[1]就是nums前1項的和。

代碼如下:

class NumArray {
    public int[] getPreArray() {
        return preArray;
    }

    //記錄一個前綴和數組,避免sumRange重複的for
    private int[] preArray;
    public NumArray(int[] nums) {
        preArray = new int[nums.length + 1];
        // 計算 nums 的累加和
        for (int i = 1; i < preArray.length; i++) {
            preArray[i] = preArray[i - 1] + nums[i - 1];
        }
    }

    public int sumRange(int left, int right) {
        int result=preArray[right+1]-preArray[left];
        return result;
    }
}

304. 二維區域和檢索 - 矩陣不可變

如果是二維數組的前綴和如何構建和使用呢?

比如leetcode 304. 二維區域和檢索 - 矩陣不可變

給定一個二維矩陣 matrix,以下類型的多個請求:

  • 計算其子矩形範圍內元素的總和,該子矩陣的 左上角(row1, col1)右下角(row2, col2)

實現 NumMatrix 類:

  • NumMatrix(int[][] matrix) 給定整數矩陣 matrix 進行初始化
  • int sumRegion(int row1, int col1, int row2, int col2) 返回 左上角 (row1, col1)右下角 (row2, col2) 所描述的子矩陣的元素 總和

示例 1:

image.png

輸入: 
["NumMatrix","sumRegion","sumRegion","sumRegion"]
[[[[3,0,1,4,2],[5,6,3,2,1],[1,2,0,1,5],[4,1,0,1,7],[1,0,3,0,5]]],[2,1,4,3],[1,1,2,2],[1,2,2,4]]
輸出: 
[null, 8, 11, 12]

解釋:
NumMatrix numMatrix = new NumMatrix([[3,0,1,4,2],[5,6,3,2,1],[1,2,0,1,5],[4,1,0,1,7],[1,0,3,0,5]]);
numMatrix.sumRegion(2, 1, 4, 3); // return 8 (紅色矩形框的元素總和)
numMatrix.sumRegion(1, 1, 2, 2); // return 11 (綠色矩形框的元素總和)
numMatrix.sumRegion(1, 2, 2, 4); // return 12 (藍色矩形框的元素總和)

如果本題繼續雙for循環,開銷很大,如果sumRegion使用頻繁,則可以使用一個前綴和數組存儲NumMatrix前i行前j列的和。

核心

Q:二維數組的前綴和如何構建呢?

A:行列的length各+1,然後找規律:左面的+上面的+自己-左對角線的

Q:規律怎麼找的?

A:比如上圖中的matrix(2)(2),它值為0;現在要計算前3行前3列的前綴和。

注意它左邊的2和上面的3,如果讓他倆各自位置的前綴和相加,然後再減去對角線的6位置的前綴和,就是0位置的前綴和。

如下圖所示(可以好好屢屢):
image.png

代碼如下:

class NumMatrix {
    public int[][] getPreMatrix() {
        return preMatrix;
    }

    private int[][] preMatrix;
    public NumMatrix(int[][] matrix) {
        preMatrix=new int[matrix.length+1][matrix[0].length+1];
        //構建 二維前綴和數組
        for(int i=1;i< preMatrix.length;i++){
            for (int j = 1; j < preMatrix[0].length; j++) {
                //找規律
                //左面的+上面的+自己-左對角線的
                preMatrix[i][j]=preMatrix[i][j-1]+preMatrix[i-1][j]+matrix[i-1][j-1]-preMatrix[i-1][j-1];
            }
        }
    }
    
    public int sumRegion(int row1, int col1, int row2, int col2) {
        return preMatrix[row2+1][col2+1] - preMatrix[row1][col2+1] - preMatrix[row2+1][col1] + preMatrix[row1][col1];
    }

    public static void main(String[] args) {
        int[][] matrix = {
                {3, 0, 1, 4, 2},
                {5, 6, 3, 2, 1},
                {1, 2, 0, 1, 5},
                {4, 1, 0, 1, 7},
                {1, 0, 3, 0, 5}
        };

        NumMatrix numMatrix = new NumMatrix(matrix);
        System.out.println(Arrays.deepToString(numMatrix.getPreMatrix()));
        System.out.println(numMatrix.sumRegion(2, 1, 4, 3));

    }
}
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.