Java  

Smallest Non-Zero Number | Greedy + Reverse Traversal

Problem Statement

You are given an integer array arr[] and an initial value x.

The value x is processed sequentially with every element in the array using the following rules:

  • If x > arr[i], then

x = x + (x - arr[i])
  • Otherwise,

x = x - (arr[i] - x)

Your task is to find the smallest non-negative value of x such that during the entire process, x never becomes negative.

Example

Input

arr = [3, 4, 3, 2, 4]

Output

4

Explanation

Start with x = 4.

StepArray ElementFormulaNew x
Initial--4
132×4−35
242×5−46
332×6−39
422×9−216
542×16−428

The value of x never becomes negative.

Understanding the Operation

At first glance, the problem seems to have two different cases.

Case 1

If

x > arr[i]

then

x = x + (x - arr[i])

Simplifying,

x = 2x - arr[i]

Case 2

If

x <= arr[i]

then

x = x - (arr[i] - x)

Again,

x = 2x - arr[i]

Important Observation

Both conditions produce the same mathematical formula.

Therefore, every step is simply:

x = 2*x - arr[i]

The only thing we must ensure is:

x never becomes negative

Why Work Backwards?

Suppose after processing an element we need at least:

need

to safely process the remaining array.

Before processing the current element,

2*x - arr[i] >= need

Rearranging,

2*x >= need + arr[i]

x >= (need + arr[i]) / 2

Since x must be an integer, we take the ceiling.

x = ceil((need + arr[i]) / 2)

Instead of guessing the answer from the beginning, we calculate the minimum required value from the last element to the first.

Greedy Idea

Maintain a variable:

need

where:

need = minimum value required before processing the current element

Initially,

need = 0

because after processing the last element, we only require the value to remain non-negative.

For every element from right to left,

need = ceil((need + arr[i]) / 2)

Dry Run

Example 1

arr = [3,4,3,2,4]

Start:

need = 0

Last Element = 4

need = ceil((0+4)/2)

need = 2

Element = 2

need = ceil((2+2)/2)

need = 2

Element = 3

need = ceil((2+3)/2)

need = 3

Element = 4

need = ceil((3+4)/2)

need = 4

Element = 3

need = ceil((4+3)/2)

need = 4

Final Answer:

4

Example 2

arr = [4,4]

Initially,

need = 0

Last element:

need = ceil((0+4)/2)

need = 2

Previous element:

need = ceil((2+4)/2)

need = 3

Answer:

3

Java Solution

class Solution {
    public int find(int[] arr) {

        // Minimum value needed after processing all elements
        int need = 0;

        // Traverse from right to left
        for (int i = arr.length - 1; i >= 0; i--) {

            // Ceiling of (need + arr[i]) / 2
            need = (need + arr[i] + 1) / 2;
        }

        return need;
    }
}

Code Explanation

Step 1

int need = 0;

Initially, after processing all elements, the required value is 0 because the final value only needs to be non-negative.

Step 2

for (int i = arr.length - 1; i >= 0; i--)

Process the array from the last element to the first.

This reverse traversal allows us to determine the minimum value needed before each operation.

Step 3

need = (need + arr[i] + 1) / 2;

This calculates:

ceil((need + arr[i]) / 2)

The expression:

(a + b + 1) / 2

is a common trick for computing the ceiling of integer division.

Examples:

ExpressionResult
(5+1)/23
(6+1)/23
(7+1)/24

Step 4

return need;

After processing every element, need becomes the smallest valid starting value.

Correctness Proof

We process the array from right to left.

For every element, we compute the minimum value required before processing it so that the remaining elements can also be processed safely.

The recurrence:

need = ceil((need + arr[i]) / 2)

guarantees that after applying:

x = 2*x - arr[i]

the resulting value is at least equal to the required value for the remaining suffix.

Since this condition is maintained for every element, the computed need is the smallest possible starting value that never allows x to become negative.

Thus, the algorithm always produces the correct answer.

Complexity Analysis

ComplexityValue
Time ComplexityO(n)
Space ComplexityO(1)
  • We traverse the array exactly once.

  • No extra array or auxiliary data structure is used.

Key Takeaways

  • Although the problem presents two update rules, both simplify to the same expression:

x = 2*x - arr[i]
  • Instead of trying different starting values, we compute the minimum required value by traversing the array from right to left.

  • The recurrence:

need = ceil((need + arr[i]) / 2)

leads to an optimal O(n) greedy solution with O(1) extra space.

  • This reverse-thinking approach is a common technique for problems that ask for the smallest initial value satisfying conditions throughout a sequence.

Summary

The key insight is that both update rules simplify to the same formula, x = 2*x - arr[i]. By working backwards and calculating the minimum value required before each element, we derive the recurrence need = ceil((need + arr[i]) / 2). This enables a simple greedy solution that runs in O(n) time and O(1) space while guaranteeing the smallest valid starting value of x.