Taro Logo

Replace Elements in an Array

Medium
Asked by:
Profile picture
20 views
Topics:
Arrays

You are given a 0-indexed array nums that consists of n distinct positive integers. Apply m operations to this array, where in the ith operation you replace the number operations[i][0] with operations[i][1].

It is guaranteed that in the ith operation:

  • operations[i][0] exists in nums.
  • operations[i][1] does not exist in nums.

Return the array obtained after applying all the operations.

Example 1:

Input: nums = [1,2,4,6], operations = [[1,3],[4,7],[6,1]]
Output: [3,2,7,1]
Explanation: We perform the following operations on nums:
- Replace the number 1 with 3. nums becomes [3,2,4,6].
- Replace the number 4 with 7. nums becomes [3,2,7,6].
- Replace the number 6 with 1. nums becomes [3,2,7,1].
We return the final array [3,2,7,1].

Example 2:

Input: nums = [1,2], operations = [[1,3],[2,1],[3,2]]
Output: [2,1]
Explanation: We perform the following operations to nums:
- Replace the number 1 with 3. nums becomes [3,2].
- Replace the number 2 with 1. nums becomes [3,1].
- Replace the number 3 with 2. nums becomes [2,1].
We return the array [2,1].

Constraints:

  • n == nums.length
  • m == operations.length
  • 1 <= n, m <= 105
  • All the values of nums are distinct.
  • operations[i].length == 2
  • 1 <= nums[i], operations[i][0], operations[i][1] <= 106
  • operations[i][0] will exist in nums when applying the ith operation.
  • operations[i][1] will not exist in nums when applying the ith operation.

Solution


Clarifying Questions

When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:

  1. What range of values can the elements in the input array have? Can I assume they are integers?
  2. What should be returned if the input array is empty or null?
  3. Can you provide an example input and the expected output, to ensure I understand the replacement logic?
  4. Is the replacement based on index or value? If based on value, what should happen if there are duplicate values in the array?
  5. Is there a constraint on the type of replacement allowed, and is there a guarantee that a replacement is always possible?

Brute Force Solution

Approach

The brute force approach to replacing array elements involves examining each element and figuring out its replacement individually. We will look at every possible replacement for each element and eventually settle on the correct ones. This is done without any shortcuts or optimizations.

Here's how the algorithm would work step-by-step:

  1. Start with the very first number in the list.
  2. For that number, find all other numbers in the list that come after it.
  3. Compare the first number with each of those following numbers.
  4. If a following number is bigger than the first number, remember that bigger number. If not, ignore it.
  5. If you found any bigger numbers, replace the first number with the biggest one you found. If not, replace it with -1.
  6. Move to the second number in the list, and repeat the process: compare it with every number that comes after it.
  7. Keep doing this for each number in the list, until you reach the end.
  8. The last number in the list will always be replaced with -1, because there are no numbers after it to compare with.

Code Implementation

def replace_elements_brute_force(numbers):
    list_length = len(numbers)

    for current_index in range(list_length):
        maximum_found = -1
        # Find the largest element to the right

        for comparison_index in range(current_index + 1, list_length):
            if numbers[comparison_index] > maximum_found:
                maximum_found = numbers[comparison_index]

        # Replace with maximum or -1
        if maximum_found != -1:
            numbers[current_index] = maximum_found

        else:
            numbers[current_index] = -1

    # The last element should always be -1
    numbers[list_length - 1] = -1

    return numbers

Big(O) Analysis

Time Complexity
O(n²)The algorithm iterates through each of the n elements in the input array. For each element, it then iterates through the remaining elements to its right to find the maximum value. In the worst-case scenario, for the first element we compare it with (n-1) elements, for the second (n-2), and so on, down to 0 for the last element. The total number of comparisons is approximately n * (n-1) / 2, which simplifies to O(n²).
Space Complexity
O(1)The algorithm iterates through the input array in place. It only uses a few extra variables like the current element's index and a variable to store the maximum value found so far. The amount of extra memory used does not depend on the size of the input array, N. Therefore, the space complexity is constant.

Optimal Solution

Approach

The efficient way to solve this problem is to move through the list from right to left, keeping track of the biggest value seen so far. Each position in the list is then updated with the biggest value encountered to its right.

Here's how the algorithm would work step-by-step:

  1. Start from the very last item in the list.
  2. Remember the value of the last item as the biggest value seen so far.
  3. Replace the last item with -1, since there are no more values to its right.
  4. Move to the item just before the last one.
  5. Compare this item's value with the biggest value you've seen up to now.
  6. If this item's value is bigger than the biggest value, update what you remember as the biggest value.
  7. Replace the current item with the biggest value you've seen so far.
  8. Keep going left through the list, repeating the comparison and replacement until you reach the first item.

Code Implementation

def replace_elements(arr):
    if not arr:
        return arr

    biggest_value_seen_so_far = arr[-1]
    arr[-1] = -1

    # Iterate backwards, starting from second to last element
    for i in range(len(arr) - 2, -1, -1):
        current_element = arr[i]

        # Keep track of the largest value to the right
        if current_element > biggest_value_seen_so_far:
            biggest_value_seen_so_far = current_element

        # Replace the current element with the largest to the right
        arr[i] = biggest_value_seen_so_far

    return arr

Big(O) Analysis

Time Complexity
O(n)The algorithm iterates through the input array of size n once, from right to left. During each iteration, a constant number of operations are performed: comparing the current element with the maximum seen so far and replacing the element. Therefore, the time complexity is directly proportional to the input size n, resulting in O(n).
Space Complexity
O(1)The algorithm described maintains only a single variable, 'biggest value seen so far', to track the maximum value encountered while traversing the array. This variable occupies a constant amount of space, irrespective of the array's size, which we denote as N. No additional data structures, like auxiliary arrays or hash maps, are used. Therefore, the auxiliary space complexity is constant, or O(1).

Edge Cases

Null or undefined input array
How to Handle:
Throw an IllegalArgumentException or return null, depending on the function contract.
Empty input array
How to Handle:
Return an empty array or null, depending on the specified behavior.
Array with only one element
How to Handle:
If the replacement logic involves comparing elements, the single element should remain unchanged, so return the original array.
Array with all identical elements
How to Handle:
The replacement logic should still apply correctly, potentially resulting in all elements being replaced with the same value based on the logic.
Array containing negative numbers
How to Handle:
Ensure that the replacement logic correctly handles negative numbers and comparisons, including potential overflow scenarios if performing arithmetic operations.
Array containing zero values
How to Handle:
Check if the replacement logic has any division by zero, which can cause program crash.
Very large array (memory constraints)
How to Handle:
Consider using an in-place replacement strategy or stream processing to avoid excessive memory usage.
Integer overflow during calculations
How to Handle:
Use appropriate data types (e.g., long) or modulo arithmetic to prevent integer overflow during intermediate calculations.