𝔩𝔢𝔩𝕠𝔭𝔢𝔷
Connect With Me on LinkedIn

Python Study

Sorted Squared Array

Efficient Sorting of Squared Values in an Array

Introduction

This article explores the challenge of squaring the values in a sorted array of integers and returning the results in ascending order. We'll address the unique challenge of negative numbers and examine various approaches to solve this problem efficiently.

Problem Statement

Given:

  • An array of integers sorted in ascending order

Objective:

  • Return a new array containing the squares of the original integers, sorted in ascending order

Example:

  • Input: [-4, -1, 0, 3, 10]
  • Output: [0, 1, 9, 16, 100]

Assumption:

  • The input array is not empty

Strategy and Hypothesis

The main challenge is handling negative numbers, whose squares can be larger than smaller positive ones. We'll explore strategies, from a straightforward brute-force approach to more optimized solutions that leverage the input array's sorted nature.

Implementation

Initial Attempt

def sortedSquaredArray(array):
    solution = []
    left = 0
    right = len(array) - 1

    while left < right:
        rSquared = array[right] * array[right]
        lSquared = array[left] * array[left]
        if lSquared > rSquared:
            solution.append(lSquared)
            left += 1
        elif rSquared > lSquared:
            solution.append(rSquared)
            right -= 1
        else:
            solution.append(rSquared)
            solution.append(lSquared)
            left += 1
            right -= 1

    solution.reverse()
    return solution

This initial attempt had issues with odd-numbered arrays and unnecessary complexity.

Brute Force Approach

# O(nLogn) time | O(n) space
def sortedSquaredArray(array):
    sortedSquares = [0 for _ in array]

    for idx in range(len(array)):
        value = array[idx]
        sortedSquares[idx] = value * value

    sortedSquares.sort()
    return sortedSquares

This approach is straightforward but not optimal due to the sorting step.

Optimal Time Approach

# O(n) time | O(n) space
def sortedSquaredArray(array):
    sortedSquares = [0 for _ in array]

    left = 0
    right = len(array) - 1

    for idx in reversed(range(len(array))):
        lValue = array[left]
        rValue = array[right]

        if abs(lValue) > abs(rValue):
            sortedSquares[idx] = lValue * lValue
            left += 1
        else:
            sortedSquares[idx] = rValue * rValue
            right -= 1

    return sortedSquares

This solution achieves optimal time complexity by leveraging the sorted nature of the input array.

Modified Initial Attempt

def sortedSquaredArray(array):
    solution = []
    left = 0
    right = len(array) - 1

    while left <= right:
        rSquared = array[right] * array[right]
        lSquared = array[left] * array[left]

        if lSquared > rSquared:
            solution.append(lSquared)
            left += 1
        else:
            solution.append(rSquared)
            right -= 1

    solution.reverse()
    return solution

This version corrects the issues in the initial attempt and simplifies the logic.

Optimization Analysis

Space Complexity

All solutions use O(n) space to store the result array.

Time Complexity

  • Brute Force: O(n log n) due to the sorting step
  • Optimal and Modified approaches: O(n), as they process each element once

Optimal Space & Time

The Optimal Time Approach provides the best balance:

  • O(n) time complexity: single pass through the array
  • O(n) space complexity: only uses space for the result array
  • Avoids unnecessary comparisons and leverages the input array's sorted nature

Key Takeaways

  1. Handling negative numbers is crucial when squaring sorted arrays
  2. Leveraging the input array's sorted nature can lead to more efficient solutions
  3. Two-pointer techniques can be powerful for problems involving sorted arrays
  4. Consider edge cases (like arrays with an odd number of elements) in your solution
  5. Understanding the time complexity of built-in methods (like reverse() and sort()) is important for optimization

Conclusion

Efficiently sorting squared values of a sorted array demonstrates the importance of considering the unique properties of the input data. By leveraging the array's sorted nature and using a two-pointer approach, we achieved an optimal O(n) time complexity solution.

This problem highlights the value of thinking beyond straightforward approaches and considering the specific characteristics of the input to design more efficient algorithms. As you encounter similar problems involving sorted data or transformations that might disrupt order, remember that clever use of the input's properties can often lead to optimal solutions.

Previous
Tournament Winner