Mastering Array-Based Algorithm Patterns
Jump Game: Greedy Reachability
public boolean canJump(int[] nums) {
int farthest = 0;
for (int idx = 0; idx < nums.length; idx++) {
if (idx > farthest) return false;
farthest = Math.max(farthest, idx + nums[idx]);
if (farthest >= nums.length - 1) return true;
}
return true;
}
The core idea is to maintain the maximum reachable endex farthest during a single pass. If the current index surpasses farthest, a gap exists, and the end is unreachable. Terminate early once the last index is covered.
Stock Trading: Summing Ascents
public int maxProfit(int[] prices) {
if (prices.length <= 1) return 0;
int total = 0;
int buyDay = 0, sellCandidate = 1;
while (sellCandidate < prices.length) {
if (prices[sellCandidate] >= prices[sellCandidate - 1]) {
sellCandidate++;
} else {
if (sellCandidate - 1 > buyDay) {
total += prices[sellCandidate - 1] - prices[buyDay];
}
buyDay = sellCandidate;
sellCandidate++;
}
}
if (sellCandidate - 1 > buyDay) {
total += prices[sellCandidate - 1] - prices[buyDay];
}
return total;
}
Treat each rising segment as a transaction. Two pointers track the purchase day and the current day. When a drop occurs, book the profit of the completed ascent. A final check handles a trailing rise.
Majority Element: Boyer-Moore Voting
public int majorityElement(int[] nums) {
int candidate = -1;
int votes = 0;
for (int element : nums) {
if (votes == 0) {
candidate = element;
votes = 1;
} else {
votes += (element == candidate) ? 1 : -1;
}
}
return candidate;
}
The algorithm cancels out distinct elements. Since the majority appears more than half the time, it survives this elimination process.
H-Index Computation
public int hIndex(int[] citations) {
int paperCount = citations.length;
int[] buckets = new int[paperCount + 1];
for (int c : citations) {
if (c >= paperCount) buckets[paperCount]++;
else buckets[c]++;
}
int cumulativePapers = 0;
for (int h = paperCount; h >= 0; h--) {
cumulativePapers += buckets[h];
if (cumulativePapers >= h) return h;
}
return 0;
}
Bucket citations based on their value. Sweep from the maximum possible H-index downwards, accumulating papers until the count meets the threshold.
Trapping Rain Water: Two-Pointer Bounded Volume
public int trap(int[] height) {
int left = 0, right = height.length - 1;
int maxLeft = 0, maxRight = 0;
int volume = 0;
while (left < right) {
if (height[left] < height[right]) {
maxLeft = Math.max(maxLeft, height[left]);
volume += maxLeft - height[left];
left++;
} else {
maxRight = Math.max(maxRight, height[right]);
volume += maxRight - height[right];
right--;
}
}
return volume;
}
Water trapped at any index is determined by the shorter of the tallest walls to its left and right. Two pointers inward from the ends dynamically update these boundaries.
Zigzag Conversion: Index Mapping by Cycle
public String convert(String s, int numRows) {
if (numRows == 1) return s;
StringBuilder output = new StringBuilder();
int length = s.length();
int cycle = 2 * numRows - 2;
for (int row = 0; row < numRows; row++) {
for (int base = 0; base + row < length; base += cycle) {
output.append(s.charAt(base + row));
if (row != 0 && row != numRows - 1 && base + cycle - row < length) {
output.append(s.charAt(base + cycle - row));
}
}
}
return output.toString();
}
A full zigzag cycle contains 2*numRows-2 characters. For each row, pick the vertical character and, if applicable, the diagonal character within each cycle.
Text Justification: Distributing White Space
public List<String> fullJustify(String[] words, int maxWidth) {
List<String> result = new ArrayList<>();
int idx = 0;
while (idx < words.length) {
int start = idx, lineLen = 0;
while (idx < words.length && lineLen + words[idx].length() + idx - start <= maxWidth) {
lineLen += words[idx++].length();
}
int wordCount = idx - start;
int totalSpaces = maxWidth - lineLen;
StringBuilder line = new StringBuilder();
if (idx == words.length || wordCount == 1) {
for (int i = start; i < idx; i++) {
line.append(words[i]);
if (i < idx - 1) line.append(' ');
}
line.append(spaces(maxWidth - line.length()));
} else {
int gap = totalSpaces / (wordCount - 1);
int extra = totalSpaces % (wordCount - 1);
for (int i = start; i < idx; i++) {
line.append(words[i]);
if (i < idx - 1) {
int currGap = gap + (extra-- > 0 ? 1 : 0);
line.append(spaces(currGap));
}
}
}
result.add(line.toString());
}
return result;
}
private String spaces(int n) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) sb.append(' ');
return sb.toString();
}
Word are gathered greedily until the line is full. For justified lines, base space and extra space are computed from totalSpaces and interval count. The last line is left-aligned with trailing blanks.
Rotating an Array with Reversals
public void rotate(int[] nums, int k) {
k %= nums.length;
reverse(nums, 0, nums.length - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, nums.length - 1);
}
private void reverse(int[] arr, int start, int end) {
while (start < end) {
int temp = arr[start];
arr[start++] = arr[end];
arr[end--] = temp;
}
}
A right rotation by k is equivalent to three reversals: the whole array, the first k elements, and the remaining elements.
Candy Distribution: Two-Way Constraint Satisfaction
public int candy(int[] ratings) {
int n = ratings.length;
int[] allocation = new int[n];
Arrays.fill(allocation, 1);
for (int i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) allocation[i] = allocation[i - 1] + 1;
}
for (int i = n - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1] && allocation[i] <= allocation[i + 1]) {
allocation[i] = allocation[i + 1] + 1;
}
}
int total = 0;
for (int val : allocation) total += val;
return total;
}
Ensure ascending rating constraints left-to-right, then right-to-left. The final value at each position satisfies both neighbors using minimal candies.