Welcome to Subscribe On Youtube

370. Range Addition

Description

You are given an integer length and an array updates where updates[i] = [startIdxi, endIdxi, inci].

You have an array arr of length length with all zeros, and you have some operation to apply on arr. In the ith operation, you should increment all the elements arr[startIdxi], arr[startIdxi + 1], ..., arr[endIdxi] by inci.

Return arr after applying all the updates.

 

Example 1:

Input: length = 5, updates = [[1,3,2],[2,4,3],[0,2,-2]]
Output: [-2,0,3,5,3]

Example 2:

Input: length = 10, updates = [[2,4,6],[5,6,8],[1,9,-4]]
Output: [0,-4,2,2,2,4,4,-4,-4,-4]

 

Constraints:

  • 1 <= length <= 105
  • 0 <= updates.length <= 104
  • 0 <= startIdxi <= endIdxi < length
  • -1000 <= inci <= 1000

Solutions

Solution 1

Suppose our array range is [0, n), the interval to be updated is [start, end], and the updated value is inc.

Then add inc to each number in the interval [start, end], which is equivalent to

  • Add inc to all numbers in the interval (start, n)
  • Then subtract inc from all the numbers in the interval (end+1, n)

After understanding that this conversion can be done, we still can’t update all the values in the interval every time, so we need to change the marking method.

  • The method is to add inc to the start position at the beginning of the coordinate, and add -inc to the position where end adds 1.

For example, we need to add 2 to the numbers in the new interval [1, 3], then we add 2 at the position of 1, and subtract 2 at the position of 4, so the array becomes [0, 2, 0, 0, -2].

If there is only one operation, how to get the final result? The answer is to create a cumulative sum array, which becomes [0, 2, 2, 2, 0]

We found that it is exactly equivalent to directly adding 2 to the numbers in the interval [1, 3]. Further analysis, the operation of establishing the accumulation and array actually means that the current number has an effect on the numbers in all subsequent positions.

  • Then we add 2 to the start position, which means that every number in the range of [start, n) is added 2
  • In fact, only the numbers in the [start, end] interval need to be added by 2
  • In order to eliminate this effect, we need to subtract 2 from the numbers in the [end+1, n) interval, so we subtract 2 from the end+1 position

Then when the accumulation and array is created, it is equivalent to subtracting 2 from all the numbers behind. It should be noted that end may be equal to n-1, then end+1 may be out of range, so we initialize the length of the array to n+1 to avoid the out of range.

Then according to the example in the title, we can get an array, nums = {-2, 2, 3, 2, -2, -3}, and then add it up and it is the result we require result = {-2, 0 , 3, 5, 3}

Solution 2: Binary Indexed Tree + Difference Array

The time complexity is $O(n \times \log n)$.

A Binary Indexed Tree (BIT), also known as a Fenwick Tree, can efficiently perform the following two operations:

  1. Point Update update(x, delta): Add a value $delta$ to the number at position $x$ in the sequence.
  2. Prefix Sum Query query(x): Query the sum of the interval $[1, … , x]$ in the sequence, i.e., the prefix sum up to position $x$.

The time complexity for both operations is $O(\log n)$.

  • class Solution {
        public int[] getModifiedArray(int length, int[][] updates) {
            int[] d = new int[length];
            for (var e : updates) {
                int l = e[0], r = e[1], c = e[2];
                d[l] += c;
                if (r + 1 < length) {
                    d[r + 1] -= c;
                }
            }
            for (int i = 1; i < length; ++i) {
                d[i] += d[i - 1];
            }
            return d;
        }
    }
    
    
    // Solution 2
    class BinaryIndexedTree {
        private int n;
        private int[] c;
    
        public BinaryIndexedTree(int n) {
            this.n = n;
            this.c = new int[n + 1];
        }
    
        public void update(int x, int delta) {
            for (; x <= n; x += x & -x) {
                c[x] += delta;
            }
        }
    
        public int query(int x) {
            int s = 0;
            for (; x > 0; x -= x & -x) {
                s += c[x];
            }
            return s;
        }
    }
    
    class Solution {
        public int[] getModifiedArray(int length, int[][] updates) {
            var tree = new BinaryIndexedTree(length);
            for (var e : updates) {
                int l = e[0], r = e[1], c = e[2];
                tree.update(l + 1, c);
                tree.update(r + 2, -c);
            }
            int[] ans = new int[length];
            for (int i = 0; i < length; ++i) {
                ans[i] = tree.query(i + 1);
            }
            return ans;
        }
    }
    
    
  • class Solution {
    public:
        vector<int> getModifiedArray(int length, vector<vector<int>>& updates) {
            vector<int> d(length);
            for (auto& e : updates) {
                int l = e[0], r = e[1], c = e[2];
                d[l] += c;
                if (r + 1 < length) d[r + 1] -= c;
            }
            for (int i = 1; i < length; ++i) d[i] += d[i - 1];
            return d;
        }
    };
    
    
    // Solution 2
    class BinaryIndexedTree {
    private:
        int n;
        vector<int> c;
    
    public:
        BinaryIndexedTree(int n)
            : n(n)
            , c(n + 1) {}
    
        void update(int x, int delta) {
            for (; x <= n; x += x & -x) {
                c[x] += delta;
            }
        }
    
        int query(int x) {
            int s = 0;
            for (; x > 0; x -= x & -x) {
                s += c[x];
            }
            return s;
        }
    };
    
    class Solution {
    public:
        vector<int> getModifiedArray(int length, vector<vector<int>>& updates) {
            BinaryIndexedTree* tree = new BinaryIndexedTree(length);
            for (const auto& e : updates) {
                int l = e[0], r = e[1], c = e[2];
                tree->update(l + 1, c);
                tree->update(r + 2, -c);
            }
            vector<int> ans;
            for (int i = 0; i < length; ++i) {
                ans.push_back(tree->query(i + 1));
            }
            return ans;
        }
    };
    
    
  • from itertools import accumulate
    
    class Solution:
        def getModifiedArray(self, length: int, updates: List[List[int]]) -> List[int]:
            d = [0] * length
            for l, r, c in updates:
                d[l] += c
                if r + 1 < length:
                    d[r + 1] -= c
            return list(accumulate(d))
    
    ############
    
    class Solution(object):
      def getModifiedArray(self, length, updates):
        """
        :type length: int
        :type updates: List[List[int]]
        :rtype: List[int]
        """
        ans = [0] * length
        for update in updates:
          start, end, delta = update
          ans[start] += delta
          if end + 1 < length:
            ans[end + 1] -= delta
    
        delta = 0
        for i in range(0, length):
          delta += ans[i]
          ans[i] = delta
        return ans
    
    
    # Solution 2
    class BinaryIndexedTree:
        __slots__ = "n", "c"
    
        def __init__(self, n: int):
            self.n = n
            self.c = [0] * (n + 1)
    
        def update(self, x: int, delta: int) -> None:
            while x <= self.n:
                self.c[x] += delta
                x += x & -x
    
        def query(self, x: int) -> int:
            s = 0
            while x:
                s += self.c[x]
                x -= x & -x
            return s
    
    
    class Solution:
        def getModifiedArray(self, length: int, updates: List[List[int]]) -> List[int]:
            tree = BinaryIndexedTree(length)
            for l, r, c in updates:
                tree.update(l + 1, c)
                tree.update(r + 2, -c)
            return [tree.query(i + 1) for i in range(length)]
    
    
  • func getModifiedArray(length int, updates [][]int) []int {
    	d := make([]int, length)
    	for _, e := range updates {
    		l, r, c := e[0], e[1], e[2]
    		d[l] += c
    		if r+1 < length {
    			d[r+1] -= c
    		}
    	}
    	for i := 1; i < length; i++ {
    		d[i] += d[i-1]
    	}
    	return d
    }
    
    
    // Solution 2
    type BinaryIndexedTree struct {
    	n int
    	c []int
    }
    
    func NewBinaryIndexedTree(n int) *BinaryIndexedTree {
    	return &BinaryIndexedTree{n: n, c: make([]int, n+1)}
    }
    
    func (bit *BinaryIndexedTree) update(x, delta int) {
    	for ; x <= bit.n; x += x & -x {
    		bit.c[x] += delta
    	}
    }
    
    func (bit *BinaryIndexedTree) query(x int) int {
    	s := 0
    	for ; x > 0; x -= x & -x {
    		s += bit.c[x]
    	}
    	return s
    }
    
    func getModifiedArray(length int, updates [][]int) (ans []int) {
    	bit := NewBinaryIndexedTree(length)
    	for _, e := range updates {
    		l, r, c := e[0], e[1], e[2]
    		bit.update(l+1, c)
    		bit.update(r+2, -c)
    	}
    	for i := 1; i <= length; i++ {
    		ans = append(ans, bit.query(i))
    	}
    	return
    }
    
    
  • /**
     * @param {number} length
     * @param {number[][]} updates
     * @return {number[]}
     */
    var getModifiedArray = function (length, updates) {
        const d = new Array(length).fill(0);
        for (const [l, r, c] of updates) {
            d[l] += c;
            if (r + 1 < length) {
                d[r + 1] -= c;
            }
        }
        for (let i = 1; i < length; ++i) {
            d[i] += d[i - 1];
        }
        return d;
    };
    
    
    // Solution 2
    /**
     * @param {number} length
     * @param {number[][]} updates
     * @return {number[]}
     */
    var getModifiedArray = function (length, updates) {
        class BinaryIndexedTree {
            constructor(n) {
                this.n = n;
                this.c = Array(n + 1).fill(0);
            }
    
            update(x, delta) {
                while (x <= this.n) {
                    this.c[x] += delta;
                    x += x & -x;
                }
            }
    
            query(x) {
                let s = 0;
                while (x > 0) {
                    s += this.c[x];
                    x -= x & -x;
                }
                return s;
            }
        }
    
        const bit = new BinaryIndexedTree(length);
        for (const [l, r, c] of updates) {
            bit.update(l + 1, c);
            bit.update(r + 2, -c);
        }
        return Array.from({ length }, (_, i) => bit.query(i + 1));
    };
    
    
  • function getModifiedArray(length: number, updates: number[][]): number[] {
        const d: number[] = Array(length).fill(0);
        for (const [l, r, c] of updates) {
            d[l] += c;
            if (r + 1 < length) {
                d[r + 1] -= c;
            }
        }
        for (let i = 1; i < length; ++i) {
            d[i] += d[i - 1];
        }
        return d;
    }
    
    
    // Solution 2
    class BinaryIndexedTree {
        private n: number;
        private c: number[];
    
        constructor(n: number) {
            this.n = n;
            this.c = Array(n + 1).fill(0);
        }
    
        update(x: number, delta: number): void {
            for (; x <= this.n; x += x & -x) {
                this.c[x] += delta;
            }
        }
    
        query(x: number): number {
            let s = 0;
            for (; x > 0; x -= x & -x) {
                s += this.c[x];
            }
            return s;
        }
    }
    
    function getModifiedArray(length: number, updates: number[][]): number[] {
        const bit = new BinaryIndexedTree(length);
        for (const [l, r, c] of updates) {
            bit.update(l + 1, c);
            bit.update(r + 2, -c);
        }
        return Array.from({ length }, (_, i) => bit.query(i + 1));
    }
    
    

All Problems

All Solutions