---
# System prepended metadata

title: Prefix Sum
tags: [Algorithm]

---

# Prefix Sum
###### tags: `Algorithm`

## Tutorial and example
[Concept with Leetcode examples](https://blog.csdn.net/ch_609583349/article/details/106423315)

## lc 2615

```python=
from collections import defaultdict
from typing import List

class Solution:
    def distance(self, nums: List[int]) -> List[int]:
        n = len(nums)
        ans = [0] * n

        # pass 1: contributions from the left (previous same values)
        cnt = defaultdict(int)
        ssum = defaultdict(int)  # sum of indices
        for i, x in enumerate(nums):
            ans[i] += i * cnt[x] - ssum[x]
            cnt[x] += 1
            ssum[x] += i

        # pass 2: contributions from the right (later same values)
        cnt.clear()
        ssum.clear()
        for i in range(n - 1, -1, -1):
            x = nums[i]
            ans[i] += ssum[x] - i * cnt[x]
            cnt[x] += 1
            ssum[x] += i

        return ans

```

```python=
class Solution:
    def distance(self, nums: List[int]) -> List[int]:
        """
        {
            "value": "array of index"
        }
        {
            "1": (number of indices, prefix sum)
        }
        
        # Solution1 (brute force)
        # build a map for recording same value indexes/indices
        # for each indexes run a double loop to get distance sum for each index
        # [0,2][0,3], [2,0][2,3], [3,0][3,2] O(n^2)
        
        # O(n)
        # loop twice (one forward one backward)
        # prefix_sum = sum of all the prefix indexes 
        # half_distance = current_index * num of prefix indexed - prefix_sum
        
        # forward
        [0, 2, 3]
        0: 0 
        2: 2 * 1 - 0 = 2
        3: 3 * 2 - 2 = 4     (|3-0| + |3-2|)
        # backward
        3: 0
        2: |2 * 1 - 3| = 1
        0: |0 * 2 - 5| = 5
        # [5,0,3,4,0]
        0: 5 + 0 = 5
        2: 2 + 1 = 3
        3: 4 + 0 = 4
        
        sum(|i - j|)     N number of j
        |N * i - sum(j)|
        """
        
        n = len(nums)
        result = [0] * n
        
        prefix_sum = dict() #  "value": (number of indices, prefix sum) 
        
        # forward
        # [0, 2, 3]
        # 0: 0 
        # 2: 2 * 1 - 0 = 2
        # 3: 3 * 2 - 2 = 4     (|3-0| + |3-2|)
        for i in range(n):
            if nums[i] not in prefix_sum:
                prefix_sum[nums[i]] = (1, i)
            else:
                seen_same_value_num, seen_same_value_index_sum = prefix_sum[nums[i]]
                result[i] += abs(seen_same_value_num * i - seen_same_value_index_sum)
                prefix_sum[nums[i]] = (seen_same_value_num + 1, seen_same_value_index_sum + i)
        
        # backward
        # 3: 0
        # 2: |2 * 1 - 3| = 1
        # 0: |0 * 2 - 5| = 5
        prefix_sum = dict() 
        for i in range(n-1, -1, -1):
            if nums[i] not in prefix_sum:
                prefix_sum[nums[i]] = (1, i) # result not updating -> 0
            else:
                seen_same_value_num, seen_same_value_index_sum = prefix_sum[nums[i]]
                result[i] += abs(seen_same_value_num * i - seen_same_value_index_sum)
                prefix_sum[nums[i]] = (seen_same_value_num + 1, seen_same_value_index_sum + i)
                
        return result
        
```