Skip to content

Commit b898429

Browse files
authored
Merge pull request #1017 from agarwalhimanshugaya/main
add boyer moore voting algorithm
2 parents bad9684 + 9f73c5e commit b898429

File tree

1 file changed

+399
-0
lines changed

1 file changed

+399
-0
lines changed
Lines changed: 399 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,399 @@
1+
---
2+
id: boyer-moore-majority-voting-algorithm
3+
title: Boyer Moore Majority voting algorithm
4+
sidebar_label: Boyer Majority voting algorithm
5+
tags: [python, java, c++, algorithms, array, counting]
6+
description: In this tutorial, we will learn about Moore's Voting Algorithm and its implementation in Python, Java, C++, and JavaScript with detailed explanations and examples.
7+
---
8+
9+
# Moore's Voting Algorithm
10+
The Boyer-Moore Majority Voting Algorithm is a well-known and efficient algorithm used to find the majority element in an array, i.e., an element that appears more than `n/2` times. This algorithm, initially designed by Robert S. Boyer and J Strother Moore in `1981`, is widely used in various applications, including data analysis and stream processing. However, in some scenarios, we may need to find elements that occur more than `n/k` times, where k is a positive integer. In this article, we explore the generalization of the Boyer-Moore Majority Voting Algorithm to solve this problem efficiently
11+
12+
## Problem Statement
13+
Given an array of `N` integers. Find the elements that appear more than `N/3` times in the array. If no such element exists, return an empty vector.
14+
15+
### Examples
16+
17+
**Example 1:**
18+
19+
```
20+
Input: N = 5, array[] = {1,2,2,3,2}
21+
Output: 2
22+
Explanation: Here we can see that the Count(1) = 1, Count(2) = 3 and Count(3) = 1.Therefore, the count of 2 is greater than N/3 times. Hence, 2 is the answer.
23+
24+
```
25+
26+
**Example 2:**
27+
28+
```
29+
Input: N = 6, array[] = {11,33,33,11,33,11}
30+
Output: 11 33
31+
Explanation: Here we can see that the Count(11) = 3 and Count(33) = 3. Therefore, the count of both 11 and 33 is greater than N/3 times. Hence, 11 and 33 is the answer.
32+
33+
```
34+
## Brute Force Approach
35+
36+
#### Intuition
37+
38+
If we closely observe, in the given array, there can be a maximum of two integers that can occur more than `floor(N/3)` times. Let’s understand it using the following scenario:
39+
Assume there are `8` elements in the given array. Now, if there is any majority element, it should occur more than `floor(8/3) = 2` times. So, the majority of elements should occur at least 3 times. Now, if we imagine there are 3 majority elements, then the total occurrence of them will be `3X3 = 9` i.e. greater than the size of the array. But this should not happen. That is why there can be a maximum of 2 majority elements.
40+
41+
#### Approach
42+
- We will run a loop that will select the elements of the array one by one.
43+
- Now, for each unique element, we will run another loop and count its occurrence in the given array.
44+
- If any element occurs more than the floor of (N/3), we will include it in our answer.
45+
- While traversing if we find any element that is already included in our answer, we will just skip it.
46+
47+
```c++
48+
vector<int> majorityElement(vector<int> v) {
49+
int n = v.size(); //size of the array
50+
vector<int> ls; // list of answers
51+
52+
for (int i = 0; i < n; i++) {
53+
//selected element is v[i]:
54+
// Checking if v[i] is not already
55+
// a part of the answer:
56+
if (ls.size() == 0 || ls[0] != v[i]) {
57+
int cnt = 0;
58+
for (int j = 0; j < n; j++) {
59+
// counting the frequency of v[i]
60+
if (v[j] == v[i]) {
61+
cnt++;
62+
}
63+
}
64+
65+
// check if frquency is greater than n/3:
66+
if (cnt > (n / 3))
67+
ls.push_back(v[i]);
68+
}
69+
70+
if (ls.size() == 2) break;
71+
}
72+
73+
return ls;
74+
}
75+
76+
```
77+
```java
78+
public static List<Integer> majorityElement(int []v) {
79+
int n = v.length; //size of the array
80+
List<Integer> ls = new ArrayList<>(); // list of answers
81+
82+
for (int i = 0; i < n; i++) {
83+
//selected element is v[i]:
84+
// Checking if v[i] is not already
85+
// a part of the answer:
86+
if (ls.size() == 0 || ls.get(0) != v[i]) {
87+
int cnt = 0;
88+
for (int j = 0; j < n; j++) {
89+
// counting the frequency of v[i]
90+
if (v[j] == v[i]) {
91+
cnt++;
92+
}
93+
}
94+
95+
// check if frquency is greater than n/3:
96+
if (cnt > (n / 3))
97+
ls.add(v[i]);
98+
}
99+
100+
if (ls.size() == 2) break;
101+
}
102+
103+
return ls;
104+
}
105+
106+
```
107+
```python
108+
from typing import List
109+
110+
def majorityElement(v: List[int]) -> List[int]:
111+
n = len(v) # size of the list
112+
ls = [] # list of answers
113+
114+
for i in range(n):
115+
# selected element is v[i]:
116+
# Checking if v[i] is not already
117+
# a part of the answer:
118+
if len(ls) == 0 or ls[0] != v[i]:
119+
cnt = 0
120+
for j in range(n):
121+
# counting the frequency of v[i]
122+
if v[j] == v[i]:
123+
cnt += 1
124+
125+
# check if frquency is greater than n/3:
126+
if cnt > (n // 3):
127+
ls.append(v[i])
128+
129+
if len(ls) == 2:
130+
break
131+
132+
return ls
133+
```
134+
#### Time Complexity : $O(n^2)$
135+
#### Spcae Complexity : $O(1)$
136+
137+
## Better Approach - Hashmap
138+
#### Intuition
139+
Use a better data structure to reduce the number of look-up operations and hence the time complexity. Moreover, we have been calculating the count of the same element again and again – so we have to reduce that also.
140+
141+
#### Approach
142+
- Use a hashmap and store the elements as `<key, value> `
143+
pairs. (Can also use frequency array based on the size of nums).
144+
- Here the key will be the element of the array and the
145+
value will be the number of times it occurs.
146+
- Traverse the whole array and update the occurrence of
147+
each element.
148+
- After that, check the map if the value for any element
149+
is greater than the floor of N/3.
150+
- If yes, include it in the list.
151+
- Else iterate forward.
152+
- Finally, return the list.
153+
154+
```c++
155+
vector<int> majorityElement(vector<int> v) {
156+
int n = v.size(); //size of the array
157+
vector<int> ls; // list of answers
158+
159+
//declaring a map:
160+
map<int, int> mpp;
161+
162+
// least occurrence of the majority element:
163+
int mini = int(n / 3) + 1;
164+
165+
//storing the elements with its occurnce:
166+
for (int i = 0; i < n; i++) {
167+
mpp[v[i]]++;
168+
169+
//checking if v[i] is
170+
// the majority element:
171+
if (mpp[v[i]] == mini) {
172+
ls.push_back(v[i]);
173+
}
174+
if (ls.size() == 2) break;
175+
}
176+
177+
return ls;
178+
}
179+
180+
```
181+
```java
182+
public static List<Integer> majorityElement(int []v) {
183+
int n = v.length; //size of the array
184+
List<Integer> ls = new ArrayList<>(); // list of answers
185+
186+
//declaring a map:
187+
HashMap<Integer, Integer> mpp = new HashMap<>();
188+
189+
// least occurrence of the majority element:
190+
int mini = (int)(n / 3) + 1;
191+
192+
//storing the elements with its occurnce:
193+
for (int i = 0; i < n; i++) {
194+
int value = mpp.getOrDefault(v[i], 0);
195+
mpp.put(v[i], value + 1);
196+
197+
//checking if v[i] is
198+
// the majority element:
199+
if (mpp.get(v[i]) == mini) {
200+
ls.add(v[i]);
201+
}
202+
if (ls.size() == 2) break;
203+
}
204+
205+
return ls;
206+
}
207+
```
208+
```python
209+
def majorityElement(arr):
210+
# Size of the given array
211+
n = len(arr)
212+
213+
# Count the occurrences of each element using Counter
214+
counter = Counter(arr)
215+
216+
# Searching for the majority element
217+
for num, count in counter.items():
218+
if count > (n // 2):
219+
return num
220+
221+
return -1
222+
```
223+
#### Time Complexity : $O(nlogn)$
224+
#### Spcae Complexity : $O(n)$
225+
226+
## Optimal Approach (Extended Boyer Moore’s Voting Algorithm):
227+
#### Intuition
228+
If the array contains the majority of elements, their occurrence must be greater than the `floor(N/3)`. Now, we can say that the count of minority elements and majority elements is equal up to a certain point in the array. So when we traverse through the array we try to keep track of the counts of elements and the elements themselves for which we are tracking the counts.
229+
230+
After traversing the whole array, we will check the elements stored in the variables. Then we need to check if the stored elements are the majority elements or not by manually checking their counts.
231+
232+
#### Steps
233+
- Initialize 4 variables:
234+
cnt1 & cnt2 – for tracking the counts of elements
235+
el1 & el2 – for storing the majority of elements.
236+
- Traverse through the given array.
237+
- If cnt1 is 0 and the current element is not el2 then store the current element of the array as el1 along with increasing the cnt1 value by 1.
238+
- If cnt2 is 0 and the current element is not el1 then store the current element of the array as el2 along with increasing the cnt2 value by 1.
239+
- If the current element and el1 are the same increase the cnt1 by 1.
240+
- If the current element and el2 are the same increase the cnt2 by 1.
241+
- Other than all the above cases: decrease cnt1 and cnt2 by 1.
242+
- The integers present in el1 & el2 should be the result we are expecting. So, using another loop, we will manually check their counts if they are greater than the floor(N/3).
243+
244+
## Implementing Extended Boyer Moore’s Voting Algorithm
245+
246+
### Python Implementation
247+
248+
```python
249+
def majorityElement(v: List[int]) -> List[int]:
250+
n = len(v) # size of the array
251+
252+
cnt1, cnt2 = 0, 0 # counts
253+
el1, el2 = float('-inf'), float('-inf') # element 1 and element 2
254+
255+
# applying the Extended Boyer Moore’s Voting Algorithm:
256+
for i in range(n):
257+
if cnt1 == 0 and el2 != v[i]:
258+
cnt1 = 1
259+
el1 = v[i]
260+
elif cnt2 == 0 and el1 != v[i]:
261+
cnt2 = 1
262+
el2 = v[i]
263+
elif v[i] == el1:
264+
cnt1 += 1
265+
elif v[i] == el2:
266+
cnt2 += 1
267+
else:
268+
cnt1 -= 1
269+
cnt2 -= 1
270+
271+
ls = [] # list of answers
272+
273+
# Manually check if the stored elements in
274+
# el1 and el2 are the majority elements:
275+
cnt1, cnt2 = 0, 0
276+
for i in range(n):
277+
if v[i] == el1:
278+
cnt1 += 1
279+
if v[i] == el2:
280+
cnt2 += 1
281+
282+
mini = int(n / 3) + 1
283+
if cnt1 >= mini:
284+
ls.append(el1)
285+
if cnt2 >= mini:
286+
ls.append(el2)
287+
288+
# Uncomment the following line
289+
# if it is told to sort the answer array:
290+
#ls.sort() #TC --> O(2*log2) ~ O(1);
291+
292+
return ls
293+
```
294+
295+
### Java Implementation
296+
297+
```java
298+
public static List<Integer> majorityElement(int []v) {
299+
int n = v.length; //size of the array
300+
301+
int cnt1 = 0, cnt2 = 0; // counts
302+
int el1 = Integer.MIN_VALUE; // element 1
303+
int el2 = Integer.MIN_VALUE; // element 2
304+
305+
// applying the Extended Boyer Moore's Voting Algorithm:
306+
for (int i = 0; i < n; i++) {
307+
if (cnt1 == 0 && el2 != v[i]) {
308+
cnt1 = 1;
309+
el1 = v[i];
310+
} else if (cnt2 == 0 && el1 != v[i]) {
311+
cnt2 = 1;
312+
el2 = v[i];
313+
} else if (v[i] == el1) cnt1++;
314+
else if (v[i] == el2) cnt2++;
315+
else {
316+
cnt1--; cnt2--;
317+
}
318+
}
319+
320+
List<Integer> ls = new ArrayList<>(); // list of answers
321+
322+
// Manually check if the stored elements in
323+
// el1 and el2 are the majority elements:
324+
cnt1 = 0; cnt2 = 0;
325+
for (int i = 0; i < n; i++) {
326+
if (v[i] == el1) cnt1++;
327+
if (v[i] == el2) cnt2++;
328+
}
329+
330+
int mini = (int)(n / 3) + 1;
331+
if (cnt1 >= mini) ls.add(el1);
332+
if (cnt2 >= mini) ls.add(el2);
333+
334+
// Uncomment the following line
335+
// if it is told to sort the answer array:
336+
//Collections.sort(ls); //TC --> O(2*log2) ~ O(1);
337+
338+
return ls;
339+
}
340+
```
341+
342+
### C++ Implementation
343+
344+
```cpp
345+
vector<int> majorityElement(vector<int> v) {
346+
int n = v.size(); //size of the array
347+
348+
int cnt1 = 0, cnt2 = 0; // counts
349+
int el1 = INT_MIN; // element 1
350+
int el2 = INT_MIN; // element 2
351+
352+
// applying the Extended Boyer Moore's Voting Algorithm:
353+
for (int i = 0; i < n; i++) {
354+
if (cnt1 == 0 && el2 != v[i]) {
355+
cnt1 = 1;
356+
el1 = v[i];
357+
}
358+
else if (cnt2 == 0 && el1 != v[i]) {
359+
cnt2 = 1;
360+
el2 = v[i];
361+
}
362+
else if (v[i] == el1) cnt1++;
363+
else if (v[i] == el2) cnt2++;
364+
else {
365+
cnt1--, cnt2--;
366+
}
367+
}
368+
369+
vector<int> ls; // list of answers
370+
371+
// Manually check if the stored elements in
372+
// el1 and el2 are the majority elements:
373+
cnt1 = 0, cnt2 = 0;
374+
for (int i = 0; i < n; i++) {
375+
if (v[i] == el1) cnt1++;
376+
if (v[i] == el2) cnt2++;
377+
}
378+
379+
int mini = int(n / 3) + 1;
380+
if (cnt1 >= mini) ls.push_back(el1);
381+
if (cnt2 >= mini) ls.push_back(el2);
382+
383+
// Uncomment the following line
384+
// if it is told to sort the answer array:
385+
// sort(ls.begin(), ls.end()); //TC --> O(2*log2) ~ O(1);
386+
387+
return ls;
388+
}
389+
```
390+
391+
## Complexity Analysis
392+
#### Time Complexity : $O(n)$
393+
#### Space Complexity : $O(1)$
394+
395+
## Conclusion
396+
- Extended Boyer Moore's Voting Algorithm concludes by returning the array of element which have occurance more than $(n/3)$, if it exists, otherwise, -1.
397+
398+
399+

0 commit comments

Comments
 (0)