Core Array Algorithms: Efficient Searching, Filtering, and Transformation Techniques

Fundamental Memory Layout

Arrays store elements in contiguous memory regions, enabling constant-time indexing. While single-dimensional arrays guarantee sequential placement, multidimensional arrays in certain programming languages do not ensure row-to-row continuity. This distinction directly influences cache locality and pointer arithmetic strategies during low-level optimization.

Binary Search Implementation

Locating a target value within a sorted sequence relies on repeatedly halving the valid search interval. The algorithm's correctness depends strictly on maintaining consistent boundary definitions throughout execution. Two stendard conventions exist:

Left-Closed, Right-Closed Range [low, high]

class Solution {
public:
    int locateValue(const std::vector<int>& sequence, int searchTarget) {
        if (sequence.empty()) return -1;
        
        int lower = 0;
        int upper = static_cast<int>(sequence.size()) - 1;
        
        while (lower <= upper) {
            int midpoint = lower + (upper - lower) / 2;
            if (sequence[midpoint] > searchTarget) {
                upper = midpoint - 1;
            } else if (sequence[midpoint] < searchTarget) {
                lower = midpoint + 1;
            } else {
                return midpoint;
            }
        }
        return -1;
    }
};

Left-Closed, Right-Open Range [low, upper)

Adjusting the interval excludes the upper bound, requiring corresponding modifications to loop termination and boundary adjustments.

class Solution {
public:
    int locateValueAlt(const std::vector<int>& sequence, int searchTarget) {
        if (sequence.empty()) return -1;
        
        int lower = 0;
        int upper = static_cast<int>(sequence.size());
        
        while (lower < upper) {
            int midpoint = lower + (upper - lower) / 2;
            if (sequence[midpoint] > searchTarget) {
                upper = midpoint;
            } else if (sequence[midpoint] < searchTarget) {
                lower = midpoint + 1;
            } else {
                return midpoint;
            }
        }
        return -1;
    }
};

In-Place Element Removal

Eliminating specific values from a container while compacting remaining elements can be optimized using dual cursors. This approach overwrites target matches sequential, achieving linear time complexity.

Optimized Two-Pointer Approach

class Solution {
public:
    int filterValue(std::vector<int>& container, int excludeTarget) {
        int writeCursor = 0;
        
        for (int readCursor = 0; readCursor < static_cast<int>(container.size()); ++readCursor) {
            if (container[readCursor] != excludeTarget) {
                container[writeCursor++] = container[readCursor];
            }
        }
        return writeCursor;
    }
};

Brute-Force Alternative

Repeated shifting elements left after detecting a match demonstrates fundamental array mutation mechanics. Though functionally correct, internal realignments result in O(n²) time complexity.

class Solution {
public:
    int filterValueNaive(std::vector<int>& container, int excludeTarget) {
        int removedCount = 0;
        for (size_t i = 0; i < container.size(); ++i) {
            if (container[i] == excludeTarget) {
                ++removedCount;
                for (size_t j = i; j < container.size() - 1; ++j) {
                    container[j] = container[j + 1];
                }
                --i;
            }
        }
        return static_cast<int>(container.size()) - removedCount;
    }
};

Squaring a Sorted Array

When a non-decreasing sequence contains negative integers, squaring each element breaks the original order. Since squared magnitudes are largest at both extremes, deploying dual pointers from opposite ends allows constructing the result array backwards in descending order, achieving O(n) efficiency without additional sorting overhead.

Optimized Construction

class Solution {
public:
    std::vector<int> generateSortedSquares(std::vector<int>& sequence) {
        int n = static_cast<int>(sequence.size());
        std::vector<int> transformed(n);
        
        int head = 0;
        int tail = n - 1;
        int pos = n - 1;
        
        while (head <= tail) {
            int leftSq = sequence[head] * sequence[head];
            int rightSq = sequence[tail] * sequence[tail];
            
            if (leftSq > rightSq) {
                transformed[pos--] = leftSq;
                ++head;
            } else {
                transformed[pos--] = rightSq;
                --tail;
            }
        }
        return transformed;
    }
};

Tags: Data Structures algorithms Binary Search Two Pointers C++

Posted on Mon, 26 Oct 2026 16:48:25 +0000 by centenial