LeetCode | 370 RangeAddition

Neking發表於2024-08-02

https://github.com/dolphinmind/datastructure/tree/datastructure-array-02

分析

陣列本身的遞迴性,差分陣列的不變性和可逆性,在left索引上的操作會對當前及後續所有元素產生影響,在right+1索引上進行反操作,會消除這種影響,再進行陣列還原,可以使得,如區間加減、區間賦值,可以常數時間內完成這些操作

  • 陣列本身具有遞迴性
  • 差分陣列性質:對於任何常數c,如果將原始陣列所有元素加上c,則差分陣列不變;從一個陣列可以唯一確定其差分陣列,反之亦然

利用上面的兩個前提中,我們來看

int nums       = {8,  2,  6,  3,  1};
int difference = {8, -6,  4, -3, -2};
// 還原[1, 4]部分的差分 numsA[1] = numsA[1], numsA[2] = numsA[1] + difference[2]
int numsA      = {8, -6, -2, -5, -7};

nums[1] = numsA[0] + numsA[1] = 2
nums[2] = numsA[0] + numsA[2] = 6
nums[3] = numsA[0] + numsA[3] = 3
nums[4] = numsA[0] + numsA[4] = 1

// numsA[0] 相當於對子差分陣列進行整體+8

從上述的例子中發現了什麼規律沒有?差分陣列的子類也始終屬於差分,差分陣列進行陣列還原的過程,每個元素都對其後續所有元素具有同步影響,對差分陣列的頭部加或減一個常數,就相當於把原陣列從頭部開始直到後面所有元素進行了相應的操作,因為什麼?原陣列整體增加/減少一個常量對差分陣列本身毫無影響,而差分陣列對初始值非常敏感,

所以在差分陣列中[left, right]

  • left索引下的陣列元素上進行常數增減操作,就是對left索引之後的原陣列所有資料元素進行對應操作
  • right索引後續陣列元素要消除這種傳遞性,就需要進行反操作

主類

Difference工具類

package com.github.dolphinmind.array.utils;

/**
 * @author dolphinmind
 * @ClassName Difference
 * @description 差分陣列
 *              性質:對於任何常數c,如果將原始陣列的所有元素加上c,則差分陣列不變
 *              即arr[i] -> arr[i] + c 不改變 diff陣列
 * @date 2024/8/2
 */

public class Difference {

    private int[] diff;

    public Difference(int[] nums) {
        assert nums.length > 0;
        diff = new int[nums.length];

        // 初始值保持不變
        diff[0] = nums[0];
        for (int i = 1; i < nums.length; i++) {
            diff[i] = nums[i] - nums[i-1];
        }
    }

    /**
     * 給閉區間[i,j]增加val(可以是負數)
     */
    public void increment(int i, int j, int val) {
        diff[i] += val;
        // 邊界判斷
        if (j + 1 < diff.length) {
            diff[j+1] -= val;
        }
    }

    /**
     * 返回復原陣列
     * @return
     */
    public int[] result() {
        int[] res = new int[diff.length];
        res[0] = diff[0];

        for (int i = 1; i < diff.length; i++) {
            res[i] = res[i-1] + diff[i];
        }

        return res;
    }
}

RangeAddition類

package com.github.dolphinmind.array;

import com.github.dolphinmind.array.utils.Difference;

/**
 * @author dolphinmind
 * @ClassName RangeAddition
 * @description 370 區間加法
 *
 * 輸入: length = 5, updates = [[1,3,2],[2,4,3],[0,2,-2]]
 * 輸出: [-2,0,3,5,3]
 * @date 2024/8/2
 */

public class RangeAddition {

    public int[] getModifiedArray(int length, int[][] updates) {

        // nums 初始化為全0
        int[] nums = new int[length];

        Difference difference = new Difference(nums);

        for (int[] update : updates) {
            int left     = update[0];
            int right    = update[1];
            int constant = update[2];
            difference.increment(left, right, constant);
        }

        return difference.result();
    }
}

測試類

package com.github.dolphinmind.array;

import org.junit.Test;

/**
 * @author dolphinmind
 * @ClassName RangeAdditionTest
 * @description
 * @date 2024/8/2
 */

public class RangeAdditionTest {

    @Test
    public void test_getModifiedArray() {
        int length = 5;
        int[][] updates = {{1, 3, 2}, {2, 4, 3}, {0, 2, -2}};

        int[] result = new RangeAddition().getModifiedArray(length, updates);

        printArray(result);

    }

    /**
     * @description 列印陣列
     * @param nums
     */

    public void printArray(int[] nums) {
        System.out.println();

        System.out.print("[");
        for (int item : nums) {
            System.out.print(item + " ");
        }
        System.out.print("]");
    }
}

相關文章