Array Manipulation Problems
Solve one Java logic problem at a time, then flip for the complete explanation and program.
Solve one Java logic problem at a time, then flip for the complete explanation and program.
Java Logic Development · Chapter 11 Companion Article
Fifteen manipulation problems — insertion, deletion, rotation, zero-shifting, merging, splitting, and rearrangement — each shaped by the fact that a Java array's length is fixed.
Array manipulation means changing the structure, position, or arrangement of elements inside an array. Typical operations include insertion, deletion, updating, rotation, merging, partitioning, and rearrangement.
A Java array has a fixed length after creation. Because of this:
Insert a new element at a specified index. Example:
Array: [10, 20, 30, 40]
Element: 25
Index: 2
[10, 20, 25, 30, 40]
Create an array with one extra position. Copy elements before the insertion index, place the new value, and shift the remaining elements by one position.
Java arrays cannot increase their length dynamically. For an original array of size n:
import java.util.Arrays;
public class InsertElement {
public static void main(String[] args) {
int[] arr = {10, 20, 30, 40};
int index = 2;
int value = 25;
if (index < 0 || index > arr.length) {
System.out.println("Invalid index");
return;
}
int[] result = new int[arr.length + 1];
for (int i = 0; i < index; i++) {
result[i] = arr[i];
}
result[index] = value;
for (int i = index; i < arr.length; i++) {
result[i + 1] = arr[i];
}
System.out.println(Arrays.toString(result));
}
}
[10, 20, 25, 30, 40]
Original: [10, 20, 30, 40]. Copy before index 2: [10, 20, _, _, _]. Insert 25: [10, 20, 25, _, _]. Copy remaining elements: [10, 20, 25, 30, 40].
The new array provides one additional position. Elements before the insertion point keep their indexes, while elements from the insertion point onward move one position forward.
O(n)O(n)arr.length.arr.length.Using index >= arr.length as the invalid condition would incorrectly reject insertion at the end. For insertion, index equal to arr.length is valid.
Be ready to explain why insertion into a normal Java array cannot increase the existing array's physical length.
Delete the element stored at a specified index. Example:
Array: [10, 20, 30, 40, 50]
Delete index: 2
[10, 20, 40, 50]
Create an array one position smaller and skip the element whose index must be deleted.
For an array of length n:
import java.util.Arrays;
public class DeleteElement {
public static void main(String[] args) {
int[] arr = {10, 20, 30, 40, 50};
int deleteIndex = 2;
if (deleteIndex < 0 || deleteIndex >= arr.length) {
System.out.println("Invalid index");
return;
}
int[] result = new int[arr.length - 1];
int j = 0;
for (int i = 0; i < arr.length; i++) {
if (i != deleteIndex) {
result[j++] = arr[i];
}
}
System.out.println(Arrays.toString(result));
}
}
[10, 20, 40, 50]
Target index: 2. Element at index 2: 30. Processing:
10 -> copy
20 -> copy
30 -> skip
40 -> copy
50 -> copy
Result: [10, 20, 40, 50].
Skipping exactly one source index reduces the number of copied elements from n to n - 1.
O(n)O(n)To delete by value rather than index:
If duplicate values exist, clearly define whether the first occurrence, last occurrence, or all occurrences must be deleted.
Replace an existing element at a specified index. Example: [10, 20, 30, 40]. Update index 2 with 99: [10, 20, 99, 40].
An array element can be accessed directly using its index.
Unlike insertion and deletion, updating does not change the array length. Use arr[index] = newValue; after validating the index.
import java.util.Arrays;
public class UpdateElement {
public static void main(String[] args) {
int[] arr = {10, 20, 30, 40};
int index = 2;
int newValue = 99;
if (index < 0 || index >= arr.length) {
System.out.println("Invalid index");
return;
}
arr[index] = newValue;
System.out.println(Arrays.toString(arr));
}
}
[10, 20, 99, 40]
Java arrays support direct index access. The JVM can locate the required position without scanning previous elements.
O(1)O(1)Do not confuse an index with an element value. For [10, 20, 30], index 1 refers to value 20, not value 1.
Move every element one position to the left. Move the first element to the last position. Example: [10, 20, 30, 40, 50] becomes [20, 30, 40, 50, 10].
Save the first element before shifting because its value would otherwise be overwritten.
arr[0] temporarily.arr[1] into arr[0].import java.util.Arrays;
public class LeftRotateArray {
public static void main(String[] args) {
int[] arr = {10, 20, 30, 40, 50};
if (arr.length > 1) {
int first = arr[0];
for (int i = 0; i < arr.length - 1; i++) {
arr[i] = arr[i + 1];
}
arr[arr.length - 1] = first;
}
System.out.println(Arrays.toString(arr));
}
}
[20, 30, 40, 50, 10]
Initial: [10, 20, 30, 40, 50]. Save: first = 10. Shift: [20, 30, 40, 50, 50]. Restore saved element: [20, 30, 40, 50, 10].
O(n)O(1)Left rotation is different from reversing an array. Rotation preserves cyclic ordering.
Move every element one position to the right and place the last element at index 0. Example: [10, 20, 30, 40, 50]. Result: [50, 10, 20, 30, 40].
Save the last element and perform shifting from right to left.
Shifting must start from the last position. Moving left to right would overwrite values that have not yet been copied.
import java.util.Arrays;
public class RightRotateArray {
public static void main(String[] args) {
int[] arr = {10, 20, 30, 40, 50};
if (arr.length > 1) {
int last = arr[arr.length - 1];
for (int i = arr.length - 1; i > 0; i--) {
arr[i] = arr[i - 1];
}
arr[0] = last;
}
System.out.println(Arrays.toString(arr));
}
}
[50, 10, 20, 30, 40]
Save: last = 50. Shift:
index 4 <- 40
index 3 <- 30
index 2 <- 20
index 1 <- 10
Place 50: [50, 10, 20, 30, 40].
O(n)O(1)For right shifting, do not traverse from index 0 toward the end. Earlier assignments would destroy values still required later.
Rotate an array left by k positions. Example:
Array: [1, 2, 3, 4, 5, 6, 7]
k: 3
[4, 5, 6, 7, 1, 2, 3]
Three reversals can rotate the array without requiring another array.
For left rotation by k:
For [1, 2, 3, 4, 5, 6, 7]: first reversal [3, 2, 1, 4, 5, 6, 7], second reversal [3, 2, 1, 7, 6, 5, 4], final reversal [4, 5, 6, 7, 1, 2, 3].
import java.util.Arrays;
public class RotateArrayByK {
public static void reverse(int[] arr, int left, int right) {
while (left < right) {
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6, 7};
int k = 3;
if (arr.length > 0) {
k %= arr.length;
reverse(arr, 0, k - 1);
reverse(arr, k, arr.length - 1);
reverse(arr, 0, arr.length - 1);
}
System.out.println(Arrays.toString(arr));
}
}
[4, 5, 6, 7, 1, 2, 3]
Suppose:
n = 7
k = 10
Rotating 10 positions is equivalent to rotating 10 % 7 = 3 positions. This prevents unnecessary repeated rotations.
O(n)O(1)Repeatedly rotating one position k times costs O(n × k). The reversal algorithm reduces this to O(n) with constant extra space.
Move all zero values to the end while preserving the relative order of non-zero elements. Example: [0, 1, 0, 3, 12]. Result: [1, 3, 12, 0, 0].
Keep a write index representing where the next non-zero value should be stored.
import java.util.Arrays;
public class MoveZerosToEnd {
public static void main(String[] args) {
int[] arr = {0, 1, 0, 3, 12};
int write = 0;
for (int value : arr) {
if (value != 0) {
arr[write++] = value;
}
}
while (write < arr.length) {
arr[write++] = 0;
}
System.out.println(Arrays.toString(arr));
}
}
[1, 3, 12, 0, 0]
Original: [0, 1, 0, 3, 12]. Non-zero values encountered:
1
3
12
First three positions become [1, 3, 12, _, _]. Fill remaining positions: [1, 3, 12, 0, 0].
Every non-zero element is processed in its original order, so the operation is stable.
O(n)O(1)A common weaker solution creates another array. The write-index technique solves the problem using constant additional space.
Move all zeros to the beginning while keeping non-zero elements in their original relative order. Example: [0, 1, 0, 3, 12]. Result: [0, 0, 1, 3, 12].
Process the array from right to left so that non-zero elements can be copied toward the end.
arr[write].import java.util.Arrays;
public class MoveZerosToBeginning {
public static void main(String[] args) {
int[] arr = {0, 1, 0, 3, 12};
int write = arr.length - 1;
for (int i = arr.length - 1; i >= 0; i--) {
if (arr[i] != 0) {
arr[write--] = arr[i];
}
}
while (write >= 0) {
arr[write--] = 0;
}
System.out.println(Arrays.toString(arr));
}
}
[0, 0, 1, 3, 12]
Processing backward allows values to be moved toward the end without destroying unprocessed values.
O(n)O(1)Move negative values to the beginning while preserving the original relative order of both groups. Example: [1, -2, 3, -4, -5, 6]. Result: [-2, -4, -5, 1, 3, 6].
When order must be preserved, collect negative elements first and non-negative elements afterward.
Use an auxiliary array:
import java.util.Arrays;
public class MoveNegativeElements {
public static void main(String[] args) {
int[] arr = {1, -2, 3, -4, -5, 6};
int[] temp = new int[arr.length];
int index = 0;
for (int value : arr) {
if (value < 0) {
temp[index++] = value;
}
}
for (int value : arr) {
if (value >= 0) {
temp[index++] = value;
}
}
System.arraycopy(temp, 0, arr, 0, arr.length);
System.out.println(Arrays.toString(arr));
}
}
[-2, -4, -5, 1, 3, 6]
The first pass extracts negatives in encounter order. The second pass does the same for non-negative values. Therefore, relative ordering inside each group remains unchanged.
O(n)O(n)An in-place partition can reduce extra space to O(1), but a simple swapping approach may change the relative order of elements. This trade-off is useful in interviews: preserve order usually means additional work or memory, while order-does-not-matter means partitioning using swaps.
Place even numbers first and odd numbers afterward while preserving order inside each group. Example: [7, 2, 5, 8, 4, 3]. Result: [2, 8, 4, 7, 5, 3].
Use the remainder operator to classify each value. An even number satisfies value % 2 == 0.
import java.util.Arrays;
public class SeparateEvenOdd {
public static void main(String[] args) {
int[] arr = {7, 2, 5, 8, 4, 3};
int[] result = new int[arr.length];
int index = 0;
for (int value : arr) {
if (value % 2 == 0) {
result[index++] = value;
}
}
for (int value : arr) {
if (value % 2 != 0) {
result[index++] = value;
}
}
System.out.println(Arrays.toString(result));
}
}
[2, 8, 4, 7, 5, 3]
Even values: 2, 8, 4. Odd values: 7, 5, 3. Combined: [2, 8, 4, 7, 5, 3].
O(n)O(n)The condition value % 2 == 0 works correctly for negative even values as well. For odd numbers, checking value % 2 != 0 is safer than checking only value % 2 == 1 because negative odd numbers can produce a remainder of -1.
Remove repeated values while keeping the first occurrence. Example: [4, 2, 4, 1, 2, 5]. Result: [4, 2, 1, 5].
Before adding an element to the result, check whether it has already been stored.
For every source element:
import java.util.Arrays;
public class RemoveDuplicates {
public static void main(String[] args) {
int[] arr = {4, 2, 4, 1, 2, 5};
int[] temp = new int[arr.length];
int uniqueCount = 0;
for (int value : arr) {
boolean duplicate = false;
for (int i = 0; i < uniqueCount; i++) {
if (temp[i] == value) {
duplicate = true;
break;
}
}
if (!duplicate) {
temp[uniqueCount++] = value;
}
}
int[] result = Arrays.copyOf(temp, uniqueCount);
System.out.println(Arrays.toString(result));
}
}
[4, 2, 1, 5]
Process 4: [4]. Process 2: [4, 2]. Process second 4: already present → ignore. Process 1: [4, 2, 1]. Process second 2: already present → ignore. Process 5: [4, 2, 1, 5].
Worst case:
O(n²)O(n)For an unsorted array, HashSet can detect duplicates in average O(1) lookup time. Overall average complexity becomes approximately time O(n) and space O(n). If the array is already sorted, duplicates can be removed using a two-pointer technique in O(n) time.
Always ask whether the array is sorted, order must be preserved, and extra space is allowed. Those constraints determine the best solution.
Combine two arrays into one array without assuming they are sorted. Example:
First: [10, 20, 30]
Second: [40, 50]
[10, 20, 30, 40, 50]
The merged array requires enough space for every element from both input arrays.
Required length: first.length + second.length. Copy:
first.length.import java.util.Arrays;
public class MergeTwoArrays {
public static void main(String[] args) {
int[] first = {10, 20, 30};
int[] second = {40, 50};
int[] merged = new int[first.length + second.length];
for (int i = 0; i < first.length; i++) {
merged[i] = first[i];
}
for (int i = 0; i < second.length; i++) {
merged[first.length + i] = second[i];
}
System.out.println(Arrays.toString(merged));
}
}
[10, 20, 30, 40, 50]
The second array begins exactly after the final index occupied by the first array. If first.length is 3:
second[0] -> merged[3]
second[1] -> merged[4]
O(n + m)O(n + m)where n and m are the lengths of the two arrays.
Merging arrays does not automatically mean sorting them. Concatenation [3, 1] + [5, 2] produces [3, 1, 5, 2], not [1, 2, 3, 5].
Merge two already sorted arrays and keep the result sorted. Example:
First: [1, 3, 5, 7]
Second: [2, 4, 6, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
Compare the current elements of both arrays and always copy the smaller one.
Maintain i for the first array, j for the second array, and k for the result array. At each step, if first[i] <= second[j], copy first[i]. Otherwise copy second[j]. After one array finishes, copy the remaining values from the other array.
import java.util.Arrays;
public class MergeSortedArrays {
public static void main(String[] args) {
int[] first = {1, 3, 5, 7};
int[] second = {2, 4, 6, 8};
int[] merged = new int[first.length + second.length];
int i = 0;
int j = 0;
int k = 0;
while (i < first.length && j < second.length) {
if (first[i] <= second[j]) {
merged[k++] = first[i++];
} else {
merged[k++] = second[j++];
}
}
while (i < first.length) {
merged[k++] = first[i++];
}
while (j < second.length) {
merged[k++] = second[j++];
}
System.out.println(Arrays.toString(merged));
}
}
[1, 2, 3, 4, 5, 6, 7, 8]
Compare:
1 and 2 -> take 1
3 and 2 -> take 2
3 and 4 -> take 3
5 and 4 -> take 4
5 and 6 -> take 5
7 and 6 -> take 6
7 and 8 -> take 7
First array finishes. Copy remaining: 8. Final: [1, 2, 3, 4, 5, 6, 7, 8].
O(n + m)O(n + m)A simple alternative is to concatenate arrays, then sort the merged array. That typically costs O((n + m) log(n + m)). The two-pointer method uses the fact that both inputs are already sorted and completes the merge in linear time.
This is the same fundamental merge operation used by Merge Sort.
Split an array into two parts. Example: [10, 20, 30, 40, 50, 60]. Result:
First half: [10, 20, 30]
Second half: [40, 50, 60]
Calculate the midpoint and copy the two ranges separately.
For length n: mid = n / 2. First part: index 0 to mid - 1. Second part: index mid to n - 1.
import java.util.Arrays;
public class SplitArray {
public static void main(String[] args) {
int[] arr = {10, 20, 30, 40, 50, 60};
int mid = arr.length / 2;
int[] first = Arrays.copyOfRange(arr, 0, mid);
int[] second = Arrays.copyOfRange(arr, mid, arr.length);
System.out.println("First half: " + Arrays.toString(first));
System.out.println("Second half: " + Arrays.toString(second));
}
}
First half: [10, 20, 30]
Second half: [40, 50, 60]
For [10, 20, 30, 40, 50], length 5, mid 5 / 2 = 2. Using the same logic produces:
First: [10, 20]
Second: [30, 40, 50]
The requirement must define which half receives the extra element.
O(n)O(n)Array splitting may also mean splitting into equal-sized chunks, splitting at a specified index, splitting positive and negative values, splitting even and odd values, or splitting based on a condition. The exact splitting rule should be identified before implementation.
Rearrange positive and negative values alternately, starting with a non-negative value. Example: [-1, 2, -3, 4, 5, -6, 7]. Result: [2, -1, 4, -3, 5, -6, 7].
Separate values by sign first. Then take one element from each group alternately.
Zero is treated as non-negative.
import java.util.Arrays;
public class RearrangeArray {
public static void main(String[] args) {
int[] arr = {-1, 2, -3, 4, 5, -6, 7};
int[] positives = new int[arr.length];
int[] negatives = new int[arr.length];
int positiveCount = 0;
int negativeCount = 0;
for (int value : arr) {
if (value >= 0) {
positives[positiveCount++] = value;
} else {
negatives[negativeCount++] = value;
}
}
int p = 0;
int n = 0;
int index = 0;
while (p < positiveCount && n < negativeCount) {
arr[index++] = positives[p++];
arr[index++] = negatives[n++];
}
while (p < positiveCount) {
arr[index++] = positives[p++];
}
while (n < negativeCount) {
arr[index++] = negatives[n++];
}
System.out.println(Arrays.toString(arr));
}
}
[2, -1, 4, -3, 5, -6, 7]
Positive values: [2, 4, 5, 7]. Negative values: [-1, -3, -6]. Take alternately:
2, -1
4, -3
5, -6
One positive remains: 7. Final: [2, -1, 4, -3, 5, -6, 7].
Separating values first makes alternation straightforward and preserves their relative order within each sign group.
O(n)O(n)"Rearrange array" is not a complete requirement by itself. It may mean alternating positive and negative values, placing smaller and larger values alternately, rearranging according to indexes, placing even and odd values alternately, or rearranging sorted values in maximum-minimum order. Always identify the required arrangement rule before writing code.
| Technique | Typical Problems |
|---|---|
| Direct indexing | Update element |
| Element shifting | Insert, delete, rotate |
| Temporary variable | Left/right rotation |
| Two pointers | Merge sorted arrays |
| Write pointer | Move zeros |
| Auxiliary array | Stable partitioning |
| Reversal algorithm | Rotate by k |
| Classification | Even/odd, positive/negative |
| Duplicate checking | Remove duplicates |
| Range copying | Split arrays |
An in-place algorithm modifies the original array without allocating another array proportional to the input size. Examples: update element, left rotation, right rotation, rotation using reversal, move zeros to end, move zeros to beginning. Typical extra space: O(1).
Operations where another array is often useful: inserting into a fixed-size array, deleting from a fixed-size array, stable separation of element groups, merging arrays, splitting arrays.
A rearrangement is stable when elements belonging to the same group retain their original relative order. Original: [5, -2, 7, -4]. Stable negative-first arrangement: [-2, -4, 5, 7]. The order:
-2 before -4
5 before 7
remains unchanged. Stability matters in problems such as moving zeros, separating positive and negative values, separating even and odd elements, and removing duplicates while preserving first occurrence.
For an array with length n, valid element indexes are 0 to n - 1. For update and deletion: 0 <= index < n. For insertion into a new larger array: 0 <= index <= n. The difference matters because inserting at index n means appending after the current last element.
| Problem | Time Complexity | Extra Space |
|---|---|---|
| Insert Element | O(n) | O(n) |
| Delete Element | O(n) | O(n) |
| Update Element | O(1) | O(1) |
| Left Rotate by 1 | O(n) | O(1) |
| Right Rotate by 1 | O(n) | O(1) |
| Rotate by K using reversal | O(n) | O(1) |
| Move Zeros to End | O(n) | O(1) |
| Move Zeros to Beginning | O(n) | O(1) |
| Move Negatives Stably | O(n) | O(n) |
| Separate Even/Odd Stably | O(n) | O(n) |
| Remove Duplicates without Set | O(n²) | O(n) |
| Merge Two Arrays | O(n + m) | O(n + m) |
| Merge Sorted Arrays | O(n + m) | O(n + m) |
| Split Array | O(n) | O(n) |
| Alternate Positive/Negative | O(n) | O(n) |
For normal access, index >= arr.length is invalid. For insertion, however, index == arr.length can be valid because the new element may be appended.
During right shift, traverse backward. During left shift, traverse forward. Using the wrong direction can overwrite a value before it has been copied.
Operations using arr[0] or arr[arr.length - 1] must account for an empty array.
Before rotating by k: k %= arr.length; This handles k values greater than the array size.
Combining two arrays and combining two sorted arrays are different problems. Sorted arrays allow an O(n + m) two-pointer solution.
Swap-based partitioning can be fast and memory-efficient, but it may violate a requirement to preserve original ordering.
Before solving an array manipulation problem, identify:
O(n) time expected?These details often determine whether the correct technique is shifting, partitioning, reversal, two pointers, or an auxiliary array.