1909. Remove One Element to Make the Array Strictly Increasing
Problem Description
Given an array nums
of integers, you need to determine if there is one element which can be removed to make the array strictly increasing. An array is strictly increasing if each element is greater than the previous one (nums[i] > nums[i - 1]
for all i
from 1 to nums.length - 1
). The goal is to return true
if the array can be made strictly increasing by removing exactly one element; otherwise, return false
. It's also important to note that if the array is already strictly increasing without any removals, the answer should be true
.
Intuition
The solution approach involves two key observations:
- If we encounter a pair of elements where the current element is not greater than its predecessor (
nums[i] <= nums[i-1]
), it presents a potential violation of the strictly increasing condition. - To resolve this violation, we have two choices: either remove the current element (
nums[i]
) or the previous element (nums[i-1]
). After making the removal, we should check if the rest of the array is strictly increasing.
The function check(nums, i)
takes care of evaluating whether the array nums
becomes strictly increasing if the element at index i
is removed. It iterates through the array and skips over the index i
. As it iterates, it maintains a prev
value that stores the last valid number in the sequence. If prev
becomes greater than or equal to the current number in the sequence at any point, that means the sequence is not strictly increasing, so it returns false
. If it finishes the loop without finding such a scenario, it means the sequence is strictly increasing, and it returns true
.
With these observations in hand, the main portion of the code starts checking elements from the beginning of the array. When it finds a violation where nums[i - 1] >= nums[i]
, it knows it's time to check the two possibilities: removing nums[i - 1]
or nums[i]
. It calls the check
function for these two indices and returns true
if either of these checks returns true
, reflecting that the array could indeed be made strictly increasing by removing one of those elements.
Solution Approach
The Python code provided defines a Solution
class with a method canBeIncreasing
, which takes an integer list nums
as input and returns a boolean indicating whether the array can become strictly increasing by removing exactly one element.
Here's a step-by-step walkthrough of the implementation:
-
A helper function
check(nums, i)
is defined, which takes the arraynums
and an indexi
. This function is responsible for checking if the array can be strictly increasing by ignoring the element at indexi
. To do that:- It initializes a variable
prev
to-inf
(negative infinity) to act as the comparator for the first element (since any integer will be greater than-inf
). - It then iterates over all the elements in
nums
and skips the element at the indexi
. For each elementnum
, it checks ifprev
is greater than or equal tonum
. If this condition is true at any point, it means removing the element at indexi
does not make the array strictly increasing, so it returnsfalse
. - If it completes the loop without finding any such violations, the function returns
true
, indicating that ignoring the element at indexi
results in a strictly increasing array.
- It initializes a variable
-
Within the
canBeIncreasing
method, a loop commences from the second element (i
starts at 1) and compares each element with its predecessor.- As long as the elements are in strictly increasing order (
nums[i - 1] < nums[i]
), the loop continues. - When a non-increasing pair is found, the code checks two cases by invoking the
check
function: one wherenums[i - 1]
is ignored (by passingi - 1
) and one wherenums[i]
is ignored (by passingi
).
- As long as the elements are in strictly increasing order (
-
The result of the method is the logical OR between these two checks:
check(nums, i - 1)
confirms if the sequence is strictly increasing by ignoring the pre-violation element.check(nums, i)
confirms if the sequence is strictly increasing by ignoring the post-violation element.- If either check returns
true
, the whole methodcanBeIncreasing
returnstrue
, indicating the given array can be made strictly increasing by removing one element. If both checks returnfalse
, the method returnsfalse
.
In terms of algorithms and patterns, this approach employs a greedy
strategy, testing if the removal of just one element at the point of violation can make the entire array strictly increasing. No advanced data structures are used, just elementary array and control flow manipulation.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's take an example array nums = [1, 3, 2, 4]
to illustrate the solution approach.
-
We start by iterating through the array from the second element. We compare each element with the one before it.
-
In the first iteration, we have
nums[0] = 1
andnums[1] = 3
. Since1 < 3
, the array is strictly increasing so far, and no action is needed. -
In the second iteration, we see
nums[1] = 3
andnums[2] = 2
.3
is not less than2
, which violates our strictly increasing condition. This is our potential problem area. -
We now have two scenarios to check:
- Remove the previous element and check if the new array (ignoring
nums[1]
) is strictly increasing ([1, 2, 4]
). - Remove the current element and check if the new array (ignoring
nums[2]
) is strictly increasing ([1, 3, 4]
).
- Remove the previous element and check if the new array (ignoring
-
We call our helper function
check(nums, i)
for both scenarios:check(nums, 1)
would ignorenums[1] = 3
, resulting in[1, 2, 4]
. The sequence is strictly increasing, so this returnstrue
.check(nums, 2)
would ignorenums[2] = 2
, resulting in[1, 3, 4]
. This sequence is also strictly increasing, so this would also returntrue
.
-
Since removing
nums[1]
(which is3
) results in a strictly increasing array, we don't need to check further. We can returntrue
.
The implementation would look something like this in Python:
class Solution:
def canBeIncreasing(self, nums):
def check(nums, i):
prev = float('-inf')
for k, num in enumerate(nums):
if k == i:
continue
if prev >= num:
return False
prev = num
return True
for i in range(1, len(nums)):
if nums[i-1] >= nums[i]:
return check(nums, i-1) or check(nums, i)
return True
# Example Usage
sol = Solution()
result = sol.canBeIncreasing([1, 3, 2, 4])
print(result) # Output should be True
In this example, our array nums = [1, 3, 2, 4]
can indeed be made strictly increasing by removing the element 3 (at index 1), and our function would correctly return true
.
Solution Implementation
1from typing import List
2
3class Solution:
4 def canBeIncreasing(self, nums: List[int]) -> bool:
5 # Helper function to check if the sequence is strictly increasing
6 # by skipping the element at index skip_index
7 def is_strictly_increasing(nums, skip_index):
8 prev_value = float('-inf')
9 for index, num in enumerate(nums):
10 # Skip the element at skip_index
11 if index == skip_index:
12 continue
13 # If current element is not greater than the previous one, sequence is not increasing
14 if prev_value >= nums[index]:
15 return False
16 prev_value = nums[index]
17 return True
18
19 # Initialize variables
20 current_index = 1
21 sequence_length = len(nums)
22
23 # Find the first instance where the sequence is not increasing
24 while current_index < sequence_length and nums[current_index - 1] < nums[current_index]:
25 current_index += 1
26
27 # Check if the sequence can be made strictly increasing
28 # by removing the element at the index just before or at the point of discrepancy
29 return (is_strictly_increasing(nums, current_index - 1) or
30 is_strictly_increasing(nums, current_index))
31
32# Example usage:
33# sol = Solution()
34# result = sol.canBeIncreasing([1, 2, 10, 5, 7])
35# print(result) # Output: True, since removing 10 makes the sequence strictly increasing
36
1class Solution {
2 // Function to check if removing one element from the array can make it strictly increasing
3 public boolean canBeIncreasing(int[] nums) {
4 int currentIndex = 1;
5 int arrayLength = nums.length;
6 // Iterate over the array to find the breaking point where the array ceases to be strictly increasing
7 for (; currentIndex < arrayLength && nums[currentIndex - 1] < nums[currentIndex]; ++currentIndex);
8
9 // Check if it's possible to make the array strictly increasing by removing the element at
10 // either the breaking point or the one before it
11 return isStrictlyIncreasingAfterRemovingIndex(nums, currentIndex - 1) ||
12 isStrictlyIncreasingAfterRemovingIndex(nums, currentIndex);
13 }
14
15 // Helper function to check if the array is strictly increasing after removing the element at index i
16 private boolean isStrictlyIncreasingAfterRemovingIndex(int[] nums, int indexToRemove) {
17 int prevValue = Integer.MIN_VALUE;
18 // Iterate over the array
19 for (int j = 0; j < nums.length; ++j) {
20 // Skip the element at the removal index
21 if (indexToRemove == j) {
22 continue;
23 }
24 // Check if the previous value is not less than the current, array can't be made strictly increasing
25 if (prevValue >= nums[j]) {
26 return false;
27 }
28 // Update previous value
29 prevValue = nums[j];
30 }
31 return true; // Array can be made strictly increasing after removing the element at indexToRemove
32 }
33}
34
1class Solution {
2public:
3 // Function to check if it's possible to have a strictly increasing sequence
4 // by removing at most one element from the given vector.
5 bool canBeIncreasing(vector<int>& nums) {
6 int i = 1; // Starting the iteration from the second element
7 int n = nums.size(); // Storing the size of nums
8 // Find the first instance where the current element is not greater than the previous one.
9 for (; i < n && nums[i - 1] < nums[i]; ++i)
10 ; // The loop condition itself ensures increment, empty body
11
12 // Check the sequences by excluding the element at (i - 1) or i
13 return isIncreasingSequence(nums, i - 1) || isIncreasingSequence(nums, i);
14 }
15
16private:
17 // Helper function to determine whether the sequence is strictly increasing
18 // if we virtually remove the element at index 'exclusionIndex'.
19 bool isIncreasingSequence(vector<int>& nums, int exclusionIndex) {
20 int prevVal = INT_MIN; // Use INT_MIN to handle the smallest integer case
21 for (int currIndex = 0; currIndex < nums.size(); ++currIndex) {
22 if (currIndex == exclusionIndex) continue; // Skip the exclusion index
23
24 // If the current element is not greater than the previous one, it's not strictly increasing.
25 if (prevVal >= nums[currIndex]) return false;
26 prevVal = nums[currIndex]; // Update the previous value
27 }
28 return true; // If all checks passed, the sequence is strictly increasing
29 }
30};
31
1function canBeIncreasing(nums: number[]): boolean {
2 // Helper function to check if the array can be strictly increasing
3 // by potentially removing the element at position p
4 const isStrictlyIncreasingWithRemoval = (positionToRemove: number): boolean => {
5 let previousValue: number | undefined = undefined; // Holds the last valid value
6 for (let index = 0; index < nums.length; index++) {
7 // Skips the element at the removal position
8 if (positionToRemove !== index) {
9 // Checks if the current element breaks the strictly increasing order
10 if (previousValue !== undefined && previousValue >= nums[index]) {
11 return false;
12 }
13 // Updates the previous value to the current one
14 previousValue = nums[index];
15 }
16 }
17 return true;
18 };
19
20 // Iterate through the input array to find the break in the strictly increasing sequence
21 for (let i = 0; i < nums.length; i++) {
22 // Check if the current element is not less than the previous one
23 if (i > 0 && nums[i - 1] >= nums[i]) {
24 // Return true if removing either the previous element or the current one
25 // can make the sequence strictly increasing
26 return isStrictlyIncreasingWithRemoval(i - 1) || isStrictlyIncreasingWithRemoval(i);
27 }
28 }
29
30 // If no breaks are found, the sequence is already strictly increasing
31 return true;
32}
33
Time and Space Complexity
The given code aims to determine if a strictly increasing sequence can be made by removing at most one element from the array nums
.
Time Complexity
The check()
function is called at most twice, regardless of the input size. It iterates through the nums
array up to n
times, where n
is the length of the array, potentially skipping one element. If we consider the length of the array as n
, the time complexity of the check()
is O(n)
because it involves a single loop through all the elements.
Since check()
is called at most twice, the time complexity of the entire canBeIncreasing()
method is O(n) + O(n)
which simplifies to O(n)
.
Space Complexity
The space complexity refers to the amount of extra space or temporary storage that an algorithm uses.
In the case of the provided Python code:
- The
check()
function uses a constant amount of additional space (only theprev
variable is used). - No additional arrays or data structures are created that depend on the input size
n
.
Therefore, the space complexity of the code is O(1)
, indicating constant space usage independent of the input size.
Learn more about how to find time and space complexity quickly using problem constraints.
What are the most two important steps in writing a depth first search function? (Select 2)
Recommended Readings
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!