We use cookies (including Google cookies) to personalize ads and analyze traffic. By continuing to use our site, you accept our Privacy Policy.

Distribute Elements Into Two Arrays II

Number: 3350

Difficulty: Hard

Paid? No

Companies: Autodesk


Problem Description

Given a 1-indexed array of integers nums, we need to distribute all its elements into two separate arrays, arr1 and arr2, by processing nums sequentially with n operations. The rules to decide where to add each nums[i] are based on a helper function greaterCount(arr, val) that counts how many elements in arr are strictly greater than val. Specifically:

  1. First, add nums[1] to arr1.
  2. Second, add nums[2] to arr2.
  3. For each subsequent element nums[i]:
    • If greaterCount(arr1, nums[i]) > greaterCount(arr2, nums[i]), add nums[i] to arr1.
    • If greaterCount(arr1, nums[i]) < greaterCount(arr2, nums[i]), add nums[i] to arr2.
    • If they are equal, add nums[i] to the array with fewer elements.
    • In case of a tie in size, add nums[i] to arr1. Finally, return the result array obtained by concatenating arr1 and arr2.

Key Insights

  • The challenge is to efficiently compute greaterCount(arr, val) repeatedly as elements are inserted.
  • A naïve scan for each query would be too slow given n can be as large as 10^5.
  • Using Binary Indexed Trees (or Segment Trees) allows efficient insertion and range queries.
  • Two BITs are maintained, one for each array, using coordinate compression since the elements can be as large as 10^9.
  • Simulation is performed in order while following the provided decision rules.

Space and Time Complexity

Time Complexity: O(n log n) due to BIT update and query operations. Space Complexity: O(n) for storing the BITs and the resulting arrays.


Solution

We simulate the process of assigning each element to either arr1 or arr2. To quickly count the number of elements greater than a given value, we use two Binary Indexed Trees (BITs). Each BIT supports:

  • update: inserting an element in O(log n).
  • query: summing frequencies in a range in O(log n).

Since the element values can be very large (up to 10^9), we use coordinate compression to map each value to a smaller range [1, m]. For each element in nums:

  1. Query BIT1 and BIT2 to obtain the number of elements in arr1 and arr2 that are greater than the current element.
  2. Decide which array to add the element to using the comparison rules.
  3. Update the corresponding BIT with the current element’s frequency.
  4. Append the element to the respective array. Finally, the result is obtained by concatenating arr1 and arr2.

The BIT data structure is the key trick that allows efficient simulation.


Code Solutions

# Python solution with line-by-line comments

# First, define the Binary Indexed Tree (Fenwick Tree) class
class BIT:
    def __init__(self, size):
        # Initialize tree of given size + 1 (1-indexed)
        self.size = size
        self.tree = [0] * (size + 1)
    
    def update(self, index, delta):
        # Update BIT with delta at position index
        while index <= self.size:
            self.tree[index] += delta
            index += index & -index
    
    def query(self, index):
        # Query cumulative frequency up to index
        result = 0
        while index > 0:
            result += self.tree[index]
            index -= index & -index
        return result
    
    def query_range(self, left, right):
        # Query frequency in range [left, right]
        return self.query(right) - self.query(left - 1)

def distribute_elements(nums):
    n = len(nums)
    # Coordinate compression: sort unique numbers
    sorted_unique = sorted(set(nums))
    comp = {num: i+1 for i, num in enumerate(sorted_unique)}
    m = len(sorted_unique)
    
    # Instantiate two BITs for arr1 and arr2
    bit1 = BIT(m)
    bit2 = BIT(m)
    
    arr1, arr2 = [], []
    
    # Insert the first two elements as per problem statement
    arr1.append(nums[0])
    bit1.update(comp[nums[0]], 1)  # update BIT for arr1
    
    arr2.append(nums[1])
    bit2.update(comp[nums[1]], 1)  # update BIT for arr2
    
    # Process remaining elements
    for i in range(2, n):
        current = nums[i]
        cur_index = comp[current]
        # Count of elements greater than current in arr1 and arr2:
        # Query range (cur_index+1, m)
        count1 = bit1.query_range(cur_index+1, m)
        count2 = bit2.query_range(cur_index+1, m)
        
        # Decide where to add the current element based on the rules
        if count1 > count2:
            arr1.append(current)
            bit1.update(cur_index, 1)
        elif count1 < count2:
            arr2.append(current)
            bit2.update(cur_index, 1)
        else:
            # When equal, check lengths of arrays
            if len(arr1) > len(arr2):
                arr2.append(current)
                bit2.update(cur_index, 1)
            elif len(arr1) < len(arr2):
                arr1.append(current)
                bit1.update(cur_index, 1)
            else:
                # Tie in length, add to arr1 as per specification
                arr1.append(current)
                bit1.update(cur_index, 1)
    
    # Return the concatenation of arr1 and arr2
    return arr1 + arr2

# Example usage:
if __name__ == "__main__":
    example_nums = [2,1,3,3]
    result = distribute_elements(example_nums)
    print(result)  # Expected output: [2, 3, 1, 3]
← Back to All Questions