Problem overview
LowerBound(int[] nums, int value) receives a sorted array and a number. It returns the smallest index at which value could be inserted so that the array stays sorted. This index is called the lower bound of the value.
Two examples show the idea:
- For
nums = [1, 2, 3, 5, 7]andvalue = 4, the answer is3. Inserting 4 at index 3 gives[1, 2, 3, 4, 5, 7], which is still sorted. - For
nums = [1, 2, 3]andvalue = 2, the answer is1. Inserting 2 at index 1 gives[1, 2, 2, 3]. Index 2 would also keep the array sorted, but the question asks for the smallest index.
The statement asks for O(n) time and O(1) extra space.
Approach: find the first element that is not smaller
In a sorted array, everything smaller than value comes first, followed by everything greater than or equal to it. The insertion point is exactly the boundary between those two groups, which means the index of the first element that is greater than or equal to value. The new number goes right before that element.
So the task becomes a scan from the left: stop at the first element that is not smaller than value, and return its index. If no element qualifies, then every element is smaller, and the value belongs after the last one.
Because the array is sorted, you could find the boundary much faster with binary search. This lesson practises the simple linear version first.
Step by step
- Loop over the indices. The answer is a position, not an element, so the loop uses an index:
for (int i = 0; i < nums.Length; i++). - Test
nums[i] >= valueand returni. The first time the test is true, the sorted order guarantees thatiis the right position, and returning stops the search immediately. The test uses>=, not>. If the value is already in the array, the answer is the index of its first occurrence, and>would skip past it. - Return
nums.Lengthafter the loop. If the loop finishes, every element is smaller thanvalue, so the value goes at the end. The index just past the last element is exactlynums.Length.
The solution in C#
class Solution {
public int LowerBound(int[] nums, int value) {
for (int i = 0; i < nums.Length; i++) {
if (nums[i] >= value) {
return i;
}
}
return nums.Length;
}
}
Notes on the C# side:
- The answer can be
nums.Length. That index is one past the end, so it isn't a position you can read from, but it is a valid place to insert. The method only returns the number. Don't use it asnums[answer]without checking. - Arrays can't grow. The method doesn't insert anything; it only reports where the value would go. Actually inserting into an array means allocating a new, longer array, whereas a
List<int>has anInsert(index, item)method that makes room for you. Lengthis a property, written with a capital L and no parentheses.
Here is the first example traced step by step, with value = 4:
i = 0: nums[0] = 1, is 1 >= 4? no
i = 1: nums[1] = 2, is 2 >= 4? no
i = 2: nums[2] = 3, is 3 >= 4? no
i = 3: nums[3] = 5, is 5 >= 4? yes, so return 3
Complexity
Time: O(n). In the worst case, no element is large enough, and the loop makes n comparisons.
Space: O(1). The method uses the loop index and nothing else.
Edge cases and common mistakes
- The value is larger than everything. For
[1, 2, 3]and value 9, the loop ends and the method returns3, the array's length. - The value is smaller than everything. For
[1, 2, 3]and value -1, the very first element passes the test, and the answer is0. - An empty array. The loop doesn't run, and the method returns
0, which is both the start and the end. - Duplicates. For
[1, 2, 2, 2, 3]and value 2, the answer is1, the first 2. Using>would return 4. - Returning -1 for "not found". This problem always has an answer. A missing value still has a position where it belongs.
- Returning the element.
return nums[i];returns the value, not the index. - Using the method on an unsorted array. The reasoning depends on the sorted order. In
[5, 1, 9], the first element that is at least 3 is the 5, but inserting 3 at index 0 doesn't describe any useful "sorted" position.
Testing
[1, 2, 3, 5, 7]with value 4 gives3.[1, 2, 3]with value 2 gives1.[1, 2, 3]with value 9 gives3.[1, 2, 3]with value -1 gives0.[]with value 1 gives0.[1, 2, 2, 2, 3]with value 2 gives1.