1550. Three Consecutive Odds
Problem Description
You are given an integer array arr
. Your task is to determine whether the array contains three consecutive odd numbers.
The problem asks you to check if there exists any position in the array where three odd numbers appear one after another. If such a sequence exists, return true
. Otherwise, return false
.
For example:
- If
arr = [2, 6, 4, 1]
, the answer would befalse
because there are no three consecutive odd numbers - If
arr = [1, 2, 34, 3, 4, 5, 7, 23, 12]
, the answer would betrue
because the numbers5, 7, 23
at indices 5, 6, and 7 are three consecutive odd numbers
The solution uses a counter approach where it tracks how many consecutive odd numbers have been encountered. When iterating through the array:
- If the current number is odd (checked using
x & 1
), increment the counter - If the counter reaches 3, we've found three consecutive odd numbers
- If the current number is even, reset the counter to 0 since the consecutive sequence is broken
Intuition
The key insight is that we need to track consecutive odd numbers as we traverse the array. Think of it like keeping a running streak - every time we encounter an odd number, our streak continues and grows. But the moment we hit an even number, the streak breaks and we must start counting from zero again.
Why does this work? Because "consecutive" means the odd numbers must appear right next to each other in the array. If there's even a single even number between them, they're no longer consecutive.
We can check if a number is odd using the bitwise AND operation x & 1
. This works because odd numbers always have their least significant bit set to 1 in binary representation, while even numbers have it set to 0. So x & 1
returns 1 for odd numbers and 0 for even numbers.
The counting approach emerges naturally from this observation:
- Start with a counter at 0
- Each odd number increments our counter (building the streak)
- Each even number resets our counter to 0 (breaking the streak)
- As soon as our counter reaches 3, we know we've found three consecutive odd numbers
This gives us a single-pass solution with O(n)
time complexity and O(1)
space complexity, as we only need to maintain one counter variable while iterating through the array once.
Solution Approach
We implement the solution using iteration and counting. The approach uses a single variable cnt
to track the current count of consecutive odd numbers as we traverse through the array.
Here's how the implementation works step by step:
-
Initialize the counter: Start with
cnt = 0
to track consecutive odd numbers. -
Iterate through the array: Process each element
x
in the array one by one. -
Check if the current number is odd: Use the bitwise AND operation
x & 1
:- If
x & 1
evaluates to 1 (truthy), the number is odd - If
x & 1
evaluates to 0 (falsy), the number is even
- If
-
Update the counter based on parity:
- If odd: Increment
cnt
by 1 (cnt += 1
)- After incrementing, check if
cnt == 3
- If yes, we've found three consecutive odd numbers, so return
True
- After incrementing, check if
- If even: Reset
cnt
to 0 since the consecutive sequence is broken
- If odd: Increment
-
Final check: If we complete the iteration without finding three consecutive odd numbers, return
False
.
The algorithm processes each element exactly once, making it efficient with O(n)
time complexity where n
is the length of the array. The space complexity is O(1)
since we only use a single counter variable regardless of the input size.
This pattern of maintaining a counter that resets on certain conditions is common in problems involving consecutive elements or streaks in arrays.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's trace through the algorithm with the array arr = [1, 2, 34, 3, 4, 5, 7, 23, 12]
.
We'll track our counter cnt
as we process each element:
Initial state: cnt = 0
Step 1: Process arr[0] = 1
- Check:
1 & 1 = 1
(odd number) - Action: Increment
cnt
to 1 - Check if
cnt == 3
? No, continue
Step 2: Process arr[1] = 2
- Check:
2 & 1 = 0
(even number) - Action: Reset
cnt
to 0
Step 3: Process arr[2] = 34
- Check:
34 & 1 = 0
(even number) - Action: Reset
cnt
to 0 (already 0)
Step 4: Process arr[3] = 3
- Check:
3 & 1 = 1
(odd number) - Action: Increment
cnt
to 1 - Check if
cnt == 3
? No, continue
Step 5: Process arr[4] = 4
- Check:
4 & 1 = 0
(even number) - Action: Reset
cnt
to 0
Step 6: Process arr[5] = 5
- Check:
5 & 1 = 1
(odd number) - Action: Increment
cnt
to 1 - Check if
cnt == 3
? No, continue
Step 7: Process arr[6] = 7
- Check:
7 & 1 = 1
(odd number) - Action: Increment
cnt
to 2 - Check if
cnt == 3
? No, continue
Step 8: Process arr[7] = 23
- Check:
23 & 1 = 1
(odd number) - Action: Increment
cnt
to 3 - Check if
cnt == 3
? Yes! ReturnTrue
We found three consecutive odd numbers (5, 7, 23) at indices 5, 6, and 7, so the function returns True
.
Solution Implementation
1class Solution:
2 def threeConsecutiveOdds(self, arr: List[int]) -> bool:
3 """
4 Check if there exist three consecutive odd numbers in the array.
5
6 Args:
7 arr: List of integers to check
8
9 Returns:
10 True if three consecutive odd numbers exist, False otherwise
11 """
12 # Counter to track consecutive odd numbers
13 consecutive_odd_count = 0
14
15 # Iterate through each element in the array
16 for number in arr:
17 # Check if the current number is odd using bitwise AND
18 # (odd numbers have LSB = 1, even numbers have LSB = 0)
19 if number & 1:
20 # Increment counter for consecutive odd numbers
21 consecutive_odd_count += 1
22
23 # If we found 3 consecutive odd numbers, return True
24 if consecutive_odd_count == 3:
25 return True
26 else:
27 # Reset counter when we encounter an even number
28 consecutive_odd_count = 0
29
30 # No three consecutive odd numbers found
31 return False
32
1class Solution {
2 /**
3 * Checks if there are three consecutive odd numbers in the array.
4 *
5 * @param arr The input integer array
6 * @return true if three consecutive odd numbers exist, false otherwise
7 */
8 public boolean threeConsecutiveOdds(int[] arr) {
9 // Counter to track consecutive odd numbers
10 int consecutiveOddCount = 0;
11
12 // Iterate through each element in the array
13 for (int currentNumber : arr) {
14 // Check if the current number is odd
15 if (currentNumber % 2 == 1) {
16 // Increment the consecutive odd counter
17 consecutiveOddCount++;
18
19 // If we've found 3 consecutive odds, return true
20 if (consecutiveOddCount == 3) {
21 return true;
22 }
23 } else {
24 // Reset counter when an even number is encountered
25 consecutiveOddCount = 0;
26 }
27 }
28
29 // No three consecutive odd numbers found
30 return false;
31 }
32}
33
1class Solution {
2public:
3 bool threeConsecutiveOdds(vector<int>& arr) {
4 // Counter to track consecutive odd numbers
5 int consecutiveOddCount = 0;
6
7 // Iterate through each element in the array
8 for (int num : arr) {
9 // Check if current number is odd using bitwise AND
10 if (num & 1) {
11 // Increment counter for odd numbers
12 consecutiveOddCount++;
13
14 // Check if we found three consecutive odds
15 if (consecutiveOddCount == 3) {
16 return true;
17 }
18 } else {
19 // Reset counter when an even number is encountered
20 consecutiveOddCount = 0;
21 }
22 }
23
24 // No three consecutive odd numbers found
25 return false;
26 }
27};
28
1/**
2 * Checks if there are three consecutive odd numbers in the array
3 * @param arr - The input array of numbers
4 * @returns true if there are three consecutive odd numbers, false otherwise
5 */
6function threeConsecutiveOdds(arr: number[]): boolean {
7 // Counter to track consecutive odd numbers
8 let consecutiveOddCount: number = 0;
9
10 // Iterate through each element in the array
11 for (const currentNumber of arr) {
12 // Check if the current number is odd using bitwise AND operation
13 // (odd numbers have their least significant bit set to 1)
14 if (currentNumber & 1) {
15 // Increment the counter for consecutive odd numbers
16 consecutiveOddCount++;
17
18 // If we've found 3 consecutive odd numbers, return true
19 if (consecutiveOddCount === 3) {
20 return true;
21 }
22 } else {
23 // Reset the counter if we encounter an even number
24 consecutiveOddCount = 0;
25 }
26 }
27
28 // No three consecutive odd numbers found
29 return false;
30}
31
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the array arr
. The algorithm iterates through the array exactly once, checking each element to determine if it's odd (using the bitwise AND operation x & 1
) and maintaining a counter. Each operation within the loop takes constant time O(1)
, so the overall time complexity is linear with respect to the input size.
The space complexity is O(1)
. The algorithm only uses a single integer variable cnt
to keep track of consecutive odd numbers, regardless of the input array size. No additional data structures are created that scale with the input, making the space usage constant.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrectly checking for odd numbers
A common mistake is using the wrong condition to check if a number is odd. Some developers might write:
if number % 2 == 1
- This fails for negative odd numbers (e.g.,-3 % 2
returns-1
in Python, not1
)if number / 2 != number // 2
- This uses floating-point division which can be inefficient
Solution: Use either number & 1
(bitwise AND) or number % 2 != 0
which work correctly for both positive and negative numbers.
2. Not resetting the counter properly
Developers might forget to reset the counter when encountering an even number, leading to incorrect counting of non-consecutive odd numbers:
# Incorrect - counts any three odd numbers, not consecutive ones count = 0 for num in arr: if num & 1: count += 1 if count == 3: return True return False
Solution: Always reset the counter to 0 when an even number is encountered to ensure we're only counting consecutive odd numbers.
3. Off-by-one errors in counter logic
Some might check for the wrong count value or increment at the wrong time:
# Incorrect - returns True after finding only 2 consecutive odds if consecutive_odd_count >= 2: return True
Solution: Ensure the counter is checked against exactly 3, and the check happens after incrementing.
4. Using sliding window when not needed
Overcomplicating with a sliding window approach:
# Unnecessarily complex
for i in range(len(arr) - 2):
if arr[i] & 1 and arr[i+1] & 1 and arr[i+2] & 1:
return True
While this works, it requires boundary checking and is less elegant.
Solution: The simple counter approach is cleaner and handles all edge cases naturally without explicit boundary checks.
What's the output of running the following function using input [30, 20, 10, 100, 33, 12]
?
1def fun(arr: List[int]) -> List[int]:
2 import heapq
3 heapq.heapify(arr)
4 res = []
5 for i in range(3):
6 res.append(heapq.heappop(arr))
7 return res
8
1public static int[] fun(int[] arr) {
2 int[] res = new int[3];
3 PriorityQueue<Integer> heap = new PriorityQueue<>();
4 for (int i = 0; i < arr.length; i++) {
5 heap.add(arr[i]);
6 }
7 for (int i = 0; i < 3; i++) {
8 res[i] = heap.poll();
9 }
10 return res;
11}
12
1class HeapItem {
2 constructor(item, priority = item) {
3 this.item = item;
4 this.priority = priority;
5 }
6}
7
8class MinHeap {
9 constructor() {
10 this.heap = [];
11 }
12
13 push(node) {
14 // insert the new node at the end of the heap array
15 this.heap.push(node);
16 // find the correct position for the new node
17 this.bubble_up();
18 }
19
20 bubble_up() {
21 let index = this.heap.length - 1;
22
23 while (index > 0) {
24 const element = this.heap[index];
25 const parentIndex = Math.floor((index - 1) / 2);
26 const parent = this.heap[parentIndex];
27
28 if (parent.priority <= element.priority) break;
29 // if the parent is bigger than the child then swap the parent and child
30 this.heap[index] = parent;
31 this.heap[parentIndex] = element;
32 index = parentIndex;
33 }
34 }
35
36 pop() {
37 const min = this.heap[0];
38 this.heap[0] = this.heap[this.size() - 1];
39 this.heap.pop();
40 this.bubble_down();
41 return min;
42 }
43
44 bubble_down() {
45 let index = 0;
46 let min = index;
47 const n = this.heap.length;
48
49 while (index < n) {
50 const left = 2 * index + 1;
51 const right = left + 1;
52
53 if (left < n && this.heap[left].priority < this.heap[min].priority) {
54 min = left;
55 }
56 if (right < n && this.heap[right].priority < this.heap[min].priority) {
57 min = right;
58 }
59 if (min === index) break;
60 [this.heap[min], this.heap[index]] = [this.heap[index], this.heap[min]];
61 index = min;
62 }
63 }
64
65 peek() {
66 return this.heap[0];
67 }
68
69 size() {
70 return this.heap.length;
71 }
72}
73
74function fun(arr) {
75 const heap = new MinHeap();
76 for (const x of arr) {
77 heap.push(new HeapItem(x));
78 }
79 const res = [];
80 for (let i = 0; i < 3; i++) {
81 res.push(heap.pop().item);
82 }
83 return res;
84}
85
Recommended Readings
Coding Interview 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
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 assets algo monster recursion jpg You first call Ben and ask
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!