Learnitweb

Non-decreasing Array


1. Problem Summary

You are given an integer array nums, and your task is to determine whether it is possible to make the array non-decreasing by modifying at most one element.

A non-decreasing array satisfies:

nums[i] <= nums[i+1]   for all i

Rules:

  • You may change at most one number
  • You may change it to any value
  • If already non-decreasing, return true

Example interpretation:
Input:

[4,2,3]

Modify 4 → 2 to get [2,2,3] → return true.

Input:

[4,2,1]

Needs at least two modifications → return false.


2. Key Insights

1. We only need to detect violations

A violation occurs when:

nums[i] > nums[i+1]

2. More than one violation → impossible

If we see two or more such drops, cannot fix with one modification.

3. When violation occurs, we must choose which number to modify

Two cases:

Case A: modify nums[i]

If:

i == 0  OR  nums[i-1] <= nums[i+1]

then lowering nums[i] works.

Case B: modify nums[i+1]

Else:

nums[i+1] = nums[i]

4. We do not need to simulate all possibilities

One pass with adjustment logic is enough.

5. Correct handling avoids accidental new violations

Choosing the right side to adjust prevents cascading failures.


3. Approach

Single pass with violation counter

Steps:

  1. Initialize violations = 0
  2. Loop through array indices from 0 to n-2
  3. If nums[i] > nums[i+1]:
    • increment violations
    • if violations > 1 → return false
    • decide modification direction:
      • if i == 0 OR nums[i-1] <= nums[i+1]:
        modify nums[i] downward (conceptually)
        else:
        modify nums[i+1] upward (conceptually)
  4. If loop completes, return true

We don’t need to truly modify array—just ensure feasibility.


4. Time and Space Complexity

Time Complexity:

O(N)

single scan through array

Space Complexity:

O(1)

no extra storage needed


5. Java Solution

class Solution {
    public boolean checkPossibility(int[] nums) {
        int violations = 0;

        for (int i = 0; i < nums.length - 1; i++) {
            if (nums[i] > nums[i + 1]) {
                violations++;
                if (violations > 1) {
                    return false;
                }

                if (i == 0 || nums[i - 1] <= nums[i + 1]) {
                    nums[i] = nums[i + 1];
                } else {
                    nums[i + 1] = nums[i];
                }
            }
        }

        return true;
    }
}

6. Dry Run Examples

Example 1

Input:

[4,2,3]

Check:
4 > 2 (violation = 1)
i == 0 → modify nums[0] → becomes 2
Resulting pattern valid

Output:

true

Example 2

Input:

[4,2,1]

Check:
4 > 2 (violation = 1)
modify nums[0] → becomes 2
Now array conceptually: [2,2,1]
Next:
2 > 1 (violation = 2) → fail

Output:

false

Example 3

Input:

[3,4,2,3]

Check:
4 > 2 (violation = 1)
nums[1] > nums[2] and nums[0] > nums[2]
so modify nums[2] → becomes 4
array becomes [3,4,4,3]
Next:
4 > 3 (violation = 2) → fail

Output:

false

Example 4

Input:

[1,2,3]

No violations

Output:

true

Example 5

Input:

[2,3,3,2,4]

Check:
3 > 2 (violation = 1)
nums[2] <= nums[4] → safe modify

Only one violation overall

Output:

true

7. Why This Solution Works

  • Detecting violations is sufficient because only one modification allowed
  • Smart choice of which element to conceptually adjust prevents chain-breaking
  • Early exit avoids unnecessary processing
  • Works for:
    • negative numbers
    • equal values
    • long sequences
    • edge boundaries

8. Common Mistakes

  1. Trying to brute force every possible modification
  2. Assuming always modify nums[i] (not always correct)
  3. Forgetting edge case at index 0
  4. Continuing after second violation
  5. Believing sorted means strictly increasing (non-decreasing allows equals)