Find All Elements Appearing More Than a Third of the Time
Solve this Problemnums, return all elements that appear MORE THAN ⌊n/3⌋ times. It's mathematically impossible for three different values to each exceed a third of the array, so the answer never has more than 2 elements — it may have 0, 1, or 2.
Counting occurrences of every value from scratch works, but it repeats the same scan for every duplicate of a non-qualifying value. The Boyer-Moore votingBoyer-Moore VotingA technique for finding elements that appear more than a fixed fraction of an array by having candidate values "cancel out" against elements that don't match them, using O(1) extra space instead of a frequency map. technique, extended to track two candidates instead of one, finds both possible answers in a single pass — followed by a quick second pass to confirm each one actually clears the bar.
Test Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
1 ≤ nums.length ≤ 5×10⁴ - ◆
-10⁹ ≤ nums[i] ≤ 10⁹
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
| 1 | class Solution { |
| 2 | public int[] majorityElementII(int[] nums) { |
| 3 | int cand1 = 0, cand2 = 1, count1 = 0, count2 = 0; |
| 4 | for (int num : nums) { |
| 5 | if (num == cand1) { |
| 6 | count1++; |
| 7 | } else if (num == cand2) { |
| 8 | count2++; |
| 9 | } else if (count1 == 0) { |
| 10 | cand1 = num; |
| 11 | count1 = 1; |
| 12 | } else if (count2 == 0) { |
| 13 | cand2 = num; |
| 14 | count2 = 1; |
| 15 | } else { |
| 16 | count1--; |
| 17 | count2--; |
| 18 | } |
| 19 | } |
| 20 | count1 = 0; |
| 21 | count2 = 0; |
| 22 | for (int num : nums) { |
| 23 | if (num == cand1) count1++; |
| 24 | else if (num == cand2) count2++; |
| 25 | } |
| 26 | List<Integer> result = new ArrayList<>(); |
| 27 | if (count1 > nums.length / 3) result.add(cand1); |
| 28 | if (count2 > nums.length / 3) result.add(cand2); |
| 29 | int[] arr = new int[result.size()]; |
| 30 | for (int i = 0; i < arr.length; i++) arr[i] = result.get(i); |
| 31 | return arr; |
| 32 | } |
| 33 | } |
| 34 |
0100Track two candidates and two counts, both starting at 0. Walk through nums once, voting.
Approach & Solutions
Brute Force
BruteFor each value in the array (skipping ones already added to the result), count its total occurrences with a nested scan and keep it if that count exceeds ⌊n/3⌋. Correct, but every value that DOESN'T qualify gets re-scanned from scratch on every one of its repeated occurrences.
O(n²)O(1)1class Solution {
2 public int[] majorityElementII(int[] nums) {
3 List<Integer> result = new ArrayList<>();
4 for (int i = 0; i < nums.length; i++) {
5 if (result.contains(nums[i])) continue;
6 int count = 0;
7 for (int j = 0; j < nums.length; j++) {
8 if (nums[j] == nums[i]) count++;
9 }
10 if (count > nums.length / 3) result.add(nums[i]);
11 }
12 int[] arr = new int[result.size()];
13 for (int i = 0; i < arr.length; i++) arr[i] = result.get(i);
14 return arr;
15 }
16}Optimal — Extended Boyer-Moore Voting
OptimalSince it's mathematically impossible for three different values to each exceed a third of the array, at most 2 values can ever qualify. Track two candidates and two counts through a single voting pass (the standard Boyer-Moore trick, extended to two slots), then verify with a second pass — surviving the vote only narrows the field to the two values that COULD be majorities, it doesn't guarantee either one actually is.
O(n)O(1)1class Solution {
2 public int[] majorityElementII(int[] nums) {
3 int cand1 = 0, cand2 = 1, count1 = 0, count2 = 0;
4 for (int num : nums) {
5 if (num == cand1) {
6 count1++;
7 } else if (num == cand2) {
8 count2++;
9 } else if (count1 == 0) {
10 cand1 = num;
11 count1 = 1;
12 } else if (count2 == 0) {
13 cand2 = num;
14 count2 = 1;
15 } else {
16 count1--;
17 count2--;
18 }
19 }
20 count1 = 0;
21 count2 = 0;
22 for (int num : nums) {
23 if (num == cand1) count1++;
24 else if (num == cand2) count2++;
25 }
26 List<Integer> result = new ArrayList<>();
27 if (count1 > nums.length / 3) result.add(cand1);
28 if (count2 > nums.length / 3) result.add(cand2);
29 int[] arr = new int[result.size()];
30 for (int i = 0; i < arr.length; i++) arr[i] = result.get(i);
31 return arr;
32 }
33}