EasyArrayFundamentals
01 / 094 min read

Concatenation of Array

Build an array of length 2n by concatenating the input array with itself.

TimeO(n)
SpaceO(n)

Given an array of n integers nums, create an array ans of length 2n such that:

ans[i] == nums[i]
ans[i + n] == nums[i]  # for 0 <= i < n

In other words, return nums concatenated with itself.

Constraints

  • Input: one line of space-separated integers (read from stdin with split_whitespace()).
  • Output: print 2n space-separated integers on one line.
  • Length: 1 <= n <= 1000 (LeetCode bounds); n = 0 is not in scope.
  • Values: integers in the input (positives, zeros, and negatives are all valid).

Input

1 2 3 4

Output

1 2 3 4 1 2 3 4

Explanation: Standard case — the input is appended to itself once.

Naive Solution

Walk through numbers twice, appending each element to a new list one at a time.

This is correct and easy to reason about, but performs 2n separate append operations and may trigger multiple buffer reallocations as the result grows.

// Walk numbers twice, pushing each element onto a new Vec.
// Time: O(n)  Space: O(n)
fn concatenate_arrays_naive(numbers: &[i64]) -> Vec<i64> {
    let mut result: Vec<i64> = Vec::new();
    for _ in 0..2 {
        for &number in numbers {
            result.push(number);
        }
    }
    result
}

Time — O(n)

Each of the 2n elements is copied once → O(n).

Space — O(n)

The result array holds 2n integers. Repeated appends may cause intermediate reallocations.

Time: two full passes over the input — acceptable, but each pass is a separate loop.

Space: growing the result with push/append may reallocate the backing buffer more than once.

Next step: pre-allocate a 2n buffer and copy each half in one or two bulk writes.

Two-Pass Solution

Pre-allocate a buffer of length 2n, then:

  1. Pass 1 — copy numbers into indices [0, n).
  2. Pass 2 — copy numbers into indices [n, 2n).

Bulk slice copies avoid per-element appends.

// Allocate a 2n Vec and copy numbers into both halves:
// positions [0, n) and positions [n, 2n) each receive the full slice.
// Time: O(n)  Space: O(n)
fn concatenate_arrays(numbers: &[i64]) -> Vec<i64> {
    let numbers_length: usize = numbers.len();
    let mut concatenated_array: Vec<i64> = vec![0; 2 * numbers_length];
    concatenated_array[..numbers_length].copy_from_slice(numbers);
    concatenated_array[numbers_length..].copy_from_slice(numbers);
    concatenated_array
}

Time — O(n)

Two linear copies of n elements each → O(n).

Space — O(n)

One pre-allocated buffer of size 2n — no reallocations.

Optimal Solution

Single pass: for each index i from 0 to n − 1, write numbers[i] to both result[i] and result[i + n] in the same iteration.

One loop fills the entire output — no second scan over the input.

// Single pass: at each index i, write numbers[i] to both halves.
// Time: O(n)  Space: O(n)
fn concatenate_arrays_optimal(numbers: &[i64]) -> Vec<i64> {
    let numbers_length: usize = numbers.len();
    let mut concatenated_array: Vec<i64> = vec![0; 2 * numbers_length];
    for idx in 0..numbers_length {
        concatenated_array[idx] = numbers[idx];
        concatenated_array[idx + numbers_length] = numbers[idx];
    }
    concatenated_array
}

Time — O(n)

One pass, two writes per iteration → O(n).

Space — O(n)

Pre-allocated buffer of size 2n.

Full source: Rust · Python