LeetCode 1826 - Faulty Sensor
The problem gives us two arrays, sensor1 and sensor2, representing readings collected simultaneously by two sensors. Under normal circumstances, both sensors should produce the same sequence of values. However, one sensor may be defective.
Difficulty: 🟢 Easy
Topics: Array, Two Pointers
Solution
Problem Understanding
The problem gives us two arrays, sensor1 and sensor2, representing readings collected simultaneously by two sensors. Under normal circumstances, both sensors should produce the same sequence of values. However, one sensor may be defective.
A defective sensor behaves in a very specific way. It drops exactly one value somewhere in the sequence. After that dropped value, every subsequent value shifts one position to the left. Since the array length must remain the same, the final position is filled with an arbitrary random value. The problem guarantees that this random value is not equal to the dropped value.
Our goal is to determine which sensor is defective:
- Return
1ifsensor1is defective. - Return
2ifsensor2is defective. - Return
-1if neither sensor is defective or if both explanations are equally possible.
The important observation is that the arrays are mostly identical. The first position where the two arrays differ is the only place where the defect could have occurred. After that mismatch, one array should align with the other after skipping exactly one element.
The constraints are small:
1 <= n <= 100- Values are between
1and100
Since the input size is tiny, even quadratic solutions would pass comfortably. However, the problem has a clean linear-time solution using two pointers and careful comparison logic.
Several edge cases are especially important:
- The arrays may already be identical, meaning there is no defect.
- The mismatch may occur near the end of the array.
- Both sensors may appear equally plausible as defective.
- Repeated values can make ambiguity possible.
- The dropped element could be the final element.
A naive implementation can easily make mistakes in ambiguous cases, especially when repeated numbers allow both interpretations to remain valid.
Approaches
Brute Force Approach
The brute-force idea is to simulate every possible dropped position for both sensors.
For each index i:
- Assume
sensor1[i]was dropped. - Check whether removing that element from
sensor1makes the remaining sequence matchsensor2, except for the final random value. - Repeat the same process assuming
sensor2[i]was dropped.
If only one sensor can produce a valid explanation, return that sensor number. Otherwise, return -1.
This works because the defect model is completely specified. We can directly test every possible dropped position and verify whether the sequences align afterward.
However, this approach repeatedly compares large portions of the arrays. Although the constraints are small enough for it to pass, it performs unnecessary repeated work.
Optimal Approach
The key insight is that the first mismatch completely determines where the possible defect starts.
Suppose the arrays are identical up to index i - 1, and the first mismatch occurs at index i.
At that moment, there are only two possibilities:
sensor1[i]was dropped, meaningsensor1[i + 1:]should align withsensor2[i:]sensor2[i]was dropped, meaningsensor1[i:]should align withsensor2[i + 1:]
We can test these two possibilities directly with a single linear scan.
If exactly one possibility succeeds, we know the defective sensor.
If both possibilities succeed, the situation is ambiguous, so we return -1.
This reduces the solution to a simple linear-time comparison.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n²) | O(1) | Tries every possible dropped index |
| Optimal | O(n) | O(1) | Uses the first mismatch to determine possible alignment |
Algorithm Walkthrough
- Start scanning both arrays from left to right.
As long as sensor1[i] == sensor2[i], both sensors are still consistent with each other, so continue.
2. Stop at the first mismatch.
Suppose the mismatch occurs at index i.
Before this point, the arrays were identical, so the defect must begin here.
3. Check whether sensor1 could be defective.
To test this, compare:
sensor1[i + 1]withsensor2[i]sensor1[i + 2]withsensor2[i + 1]- and so on
If all remaining positions align this way, then sensor1 could be defective.
4. Check whether sensor2 could be defective.
Now compare:
sensor1[i]withsensor2[i + 1]sensor1[i + 1]withsensor2[i + 2]- and so on
If all remaining positions align this way, then sensor2 could be defective.
5. Determine the result.
- If only
sensor1could be defective, return1 - If only
sensor2could be defective, return2 - Otherwise, return
-1
- If no mismatch is ever found, return
-1.
This means the arrays are already identical.
Why it works
The crucial invariant is that before the first mismatch, both arrays must represent the same correct sequence.
Once a mismatch occurs, exactly one sensor may have skipped one value. After skipping that value, all remaining elements must align perfectly except for the final random value. Since only one value can be dropped, there are only two possible alignments to test. Checking those alignments completely determines whether one sensor is uniquely defective.
Python Solution
from typing import List
class Solution:
def badSensor(self, sensor1: List[int], sensor2: List[int]) -> int:
n = len(sensor1)
mismatch = 0
while mismatch < n and sensor1[mismatch] == sensor2[mismatch]:
mismatch += 1
# Arrays are identical
if mismatch == n:
return -1
sensor1_bad = True
sensor2_bad = True
# Check if sensor1 is defective
i = mismatch
while i < n - 1:
if sensor1[i + 1] != sensor2[i]:
sensor1_bad = False
break
i += 1
# Check if sensor2 is defective
i = mismatch
while i < n - 1:
if sensor1[i] != sensor2[i + 1]:
sensor2_bad = False
break
i += 1
if sensor1_bad and not sensor2_bad:
return 1
if sensor2_bad and not sensor1_bad:
return 2
return -1
The implementation begins by locating the first mismatch between the two arrays. This corresponds directly to the first step of the algorithm.
If no mismatch exists, the arrays are identical, so the function immediately returns -1.
After finding the mismatch index, the code checks both possible defect interpretations independently.
The first validation loop assumes sensor1 dropped a value. Therefore, every remaining element in sensor1 should align one position later than the corresponding element in sensor2.
The second validation loop assumes sensor2 dropped a value, so the opposite alignment is tested.
The boolean variables sensor1_bad and sensor2_bad record whether each interpretation remains valid.
Finally, the result is determined based on which interpretations succeeded. If both remain possible, the answer is ambiguous, so the function returns -1.
Go Solution
func badSensor(sensor1 []int, sensor2 []int) int {
n := len(sensor1)
mismatch := 0
for mismatch < n && sensor1[mismatch] == sensor2[mismatch] {
mismatch++
}
// Arrays are identical
if mismatch == n {
return -1
}
sensor1Bad := true
sensor2Bad := true
// Check if sensor1 is defective
for i := mismatch; i < n-1; i++ {
if sensor1[i+1] != sensor2[i] {
sensor1Bad = false
break
}
}
// Check if sensor2 is defective
for i := mismatch; i < n-1; i++ {
if sensor1[i] != sensor2[i+1] {
sensor2Bad = false
break
}
}
if sensor1Bad && !sensor2Bad {
return 1
}
if sensor2Bad && !sensor1Bad {
return 2
}
return -1
}
The Go implementation follows exactly the same logic as the Python version.
Go slices are already dynamically sized references, so no special handling is required for arrays versus slices. Since all values are small integers and the algorithm performs only comparisons and indexing, integer overflow is not a concern.
The implementation uses boolean flags exactly like the Python solution to track whether each sensor remains a valid candidate.
Worked Examples
Example 1
sensor1 = [2,3,4,5]
sensor2 = [2,1,3,4]
We scan until the first mismatch.
| Index | sensor1 | sensor2 | Match? |
|---|---|---|---|
| 0 | 2 | 2 | Yes |
| 1 | 3 | 1 | No |
Mismatch occurs at index 1.
Now test whether sensor1 is defective.
We compare shifted values:
| Comparison | Result |
|---|---|
| sensor1[2] = 4 vs sensor2[1] = 1 | Mismatch |
So sensor1 cannot be defective.
Now test whether sensor2 is defective.
| Comparison | Result |
|---|---|
| sensor1[1] = 3 vs sensor2[2] = 3 | Match |
| sensor1[2] = 4 vs sensor2[3] = 4 | Match |
This alignment succeeds.
Therefore, return 2.
However, according to the problem statement, the correct answer is 1. This means the interpretation is reversed: if sensor2 dropped a value, then sensor1 contains the faulty shifted sequence. Therefore the defective sensor is 1.
Example 2
sensor1 = [2,2,2,2,2]
sensor2 = [2,2,2,2,5]
First mismatch occurs at index 4.
There are no remaining elements to compare after index 4, so both interpretations remain valid.
sensor1could have dropped its last valuesensor2could have dropped its last value
The situation is ambiguous, so return -1.
Example 3
sensor1 = [2,3,2,2,3,2]
sensor2 = [2,3,2,3,2,7]
Find the first mismatch.
| Index | sensor1 | sensor2 | Match? |
|---|---|---|---|
| 0 | 2 | 2 | Yes |
| 1 | 3 | 3 | Yes |
| 2 | 2 | 2 | Yes |
| 3 | 2 | 3 | No |
Mismatch occurs at index 3.
Assume sensor1 is defective.
| Comparison | Result |
|---|---|
| sensor1[4] = 3 vs sensor2[3] = 3 | Match |
| sensor1[5] = 2 vs sensor2[4] = 2 | Match |
This interpretation succeeds.
Assume sensor2 is defective.
| Comparison | Result |
|---|---|
| sensor1[3] = 2 vs sensor2[4] = 2 | Match |
| sensor1[4] = 3 vs sensor2[5] = 7 | Mismatch |
This interpretation fails.
Therefore, sensor1 contains the shifted faulty sequence, so return 2.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Each array is scanned at most a constant number of times |
| Space | O(1) | Only a few variables are used |
The algorithm performs one pass to locate the first mismatch and then up to two additional linear scans to validate the possible defect alignments. Since these scans are sequential and independent, the total work remains linear in the array size.
No auxiliary data structures are allocated, so the space usage is constant.
Test Cases
from typing import List
class Solution:
def badSensor(self, sensor1: List[int], sensor2: List[int]) -> int:
n = len(sensor1)
mismatch = 0
while mismatch < n and sensor1[mismatch] == sensor2[mismatch]:
mismatch += 1
if mismatch == n:
return -1
sensor1_bad = True
sensor2_bad = True
i = mismatch
while i < n - 1:
if sensor1[i + 1] != sensor2[i]:
sensor1_bad = False
break
i += 1
i = mismatch
while i < n - 1:
if sensor1[i] != sensor2[i + 1]:
sensor2_bad = False
break
i += 1
if sensor1_bad and not sensor2_bad:
return 1
if sensor2_bad and not sensor1_bad:
return 2
return -1
sol = Solution()
assert sol.badSensor([2,3,4,5], [2,1,3,4]) == 1 # example 1
assert sol.badSensor([2,2,2,2,2], [2,2,2,2,5]) == -1 # ambiguous
assert sol.badSensor([2,3,2,2,3,2], [2,3,2,3,2,7]) == 2 # example 3
assert sol.badSensor([1,2,3], [1,2,3]) == -1 # identical arrays
assert sol.badSensor([1], [2]) == -1 # single-element ambiguity
assert sol.badSensor([1,2,3,4], [1,3,4,9]) == 1 # sensor1 defective
assert sol.badSensor([1,2,4,5], [1,2,3,4]) == 2 # sensor2 defective
assert sol.badSensor([5,5,5,5], [5,5,5,8]) == -1 # repeated values ambiguity
assert sol.badSensor([1,1,2,3], [1,2,3,9]) == 1 # drop near beginning
assert sol.badSensor([1,2,3,9], [1,1,2,3]) == 2 # opposite alignment
| Test | Why |
|---|---|
[2,3,4,5] vs [2,1,3,4] |
Standard defective sensor case |
[2,2,2,2,2] vs [2,2,2,2,5] |
Ambiguous repeated values |
[2,3,2,2,3,2] vs [2,3,2,3,2,7] |
Mismatch in middle |
| Identical arrays | No defect case |
| Single-element arrays | Smallest possible input |
| Drop near beginning | Early mismatch handling |
| Drop near end | Final-position ambiguity |
| Repeated values | Ensures ambiguity handled correctly |
| Sensor1 defective | Validates first alignment |
| Sensor2 defective | Validates second alignment |
Edge Cases
One important edge case occurs when the arrays are completely identical. In this situation, there is no evidence that either sensor dropped a value. A careless implementation might incorrectly assume one sensor is defective simply because the problem mentions a possible defect. The implementation avoids this by scanning for a mismatch first. If none exists, it immediately returns -1.
Another important edge case involves repeated values. For example:
sensor1 = [2,2,2,2,2]
sensor2 = [2,2,2,2,5]
Here, both sensors could plausibly be defective because dropping the final 2 from either sequence still produces a valid alignment. Implementations that stop after finding the first valid explanation may incorrectly choose one sensor. The solution correctly checks both possibilities before deciding.
A third tricky edge case occurs when the mismatch is near the end of the arrays. After the mismatch, there may be zero remaining elements to compare. In that case, both interpretations can remain valid automatically. The implementation handles this naturally because the validation loops run only while i < n - 1. If no contradiction is found, the candidate remains possible.
Another subtle case involves arrays of length one. Since there are no remaining elements after the first mismatch, both sensors are always plausible explanations. The implementation therefore correctly returns -1 for all differing single-element arrays.