Problem overview
Find(int[] nums, int value) returns the index at which value appears in nums, or -1 when it isn't there. For nums = [1, 2, 4, 5] and value = 4, the answer is 2, because nums[2] is 4.
The statement asks for O(n) time and O(1) extra space, which fits the most direct approach: look at the elements one by one from the start.
Approach: check each position until you find it
This is linear search. Start at index 0, compare the element with value, and move on to the next index if they differ. The moment you find a match, you know the answer and can stop. If you get to the end of the array without a match, the value isn't there.
A plain foreach would give you each value but not its position. Since the answer is an index, the loop has to run over the indices themselves, so that i is the position and nums[i] is the value there.
Linear search works on any array, sorted or not. When an array is sorted, you can do better with binary search, but that needs the ordering. Here, nothing is assumed.
Step by step
- Loop over every index. Write
for (int i = 0; i < nums.Length; i++). The condition uses<because the last valid index isLength - 1. - Compare and return immediately. Inside the loop,
if (nums[i] == value)detects the match, andreturn i;leaves the method with the position. Returning right away also means that if the value occurs several times, you get the first index. - Return
-1after the loop. Reaching this line means noreturnran inside the loop, so no element matched. The value -1 can't be a valid index, so the caller can't confuse it with a real position.
The solution in C#
class Solution {
public int Find(int[] nums, int value) {
for (int i = 0; i < nums.Length;i++) {
if (nums[i] == value) {
return i;
}
}
return -1;
}
}
C# details worth noting:
- Every path returns a value. The compiler requires that the method returns an
inton every route. Without the finalreturn -1;, the code would not compile, because the loop might finish without returning. Lengthis a property. Writenums.Length, with a capital L and no parentheses.==compares numbers by value. Forintit does exactly what you expect. (For other types, such as strings,==also compares contents in C#, but this lesson only uses integers.)- A built-in exists.
Array.IndexOf(nums, value)does the same job and also returns -1 when the value is missing. Writing the loop yourself shows what it does inside.
Complexity
Time: O(n). In the worst case, the value is last or missing, and the loop makes n comparisons, where n is nums.Length. If the value is first, the loop stops after one comparison, but the bound for the worst case is what counts.
Space: O(1). The only extra variable is the index i.
Edge cases and common mistakes
- The value is missing. The loop ends without a return, and the method returns -1. For
[1, 2, 4, 5]and value 3, the result is-1. - An empty array. The loop doesn't run, so the answer is -1.
- Duplicates.
[4, 4]with value 4 returns0, the first index, because the method returns at the first match. - Putting
return -1inside the loop. The method would give up after the first element that doesn't match. The "not found" answer is only certain after every element has been checked, so it goes below the loop. - Returning the value instead of the index.
return nums[i];compiles but answers a different question. For the example it would return 4 instead of 2. - Using
<=in the loop condition. The last pass would readnums[nums.Length], and the program would throw anIndexOutOfRangeExceptionwhen the value isn't found earlier. - Using
=instead of==. An assignment inside theifisn't abool, so C# rejects it at compile time.
Testing
[1, 2, 4, 5]with value 4 gives2.[1, 2, 4, 5]with value 3 gives-1.[4, 4]with value 4 gives0.[7]with value 7 gives0.[]with value 1 gives-1.