Skip to main content

Topic- (Hashing) Second Highest Occuring/Frequency Element Brute Force Approach

Java · DSA · Brute Force

Find the element with the second-highest frequency using a visited array and two leader slots, el1 and el2. Watch it run step by step, see why it prints the wrong value for some inputs, and get a version that works.

01 The problem

Given an array of N non-negative integers, print the element whose frequency is the second highest. If several elements share that frequency, print the smallest. If there is no second frequency (every value appears equally often), print -1.

For [1, 2, 2, 3, 3, 3], the frequencies are 1 → 1, 2 → 2 and 3 → 3. The highest is 3 (value 3), so the answer is 2.

Type an array to compare the code below with the fixed version and the expected answer.

02 The brute-force code

The idea: walk the array with i. The first time a value shows up, mark it in visited and count its occurrences with an inner j loop. Then compare that count against the two leaders: el1 (highest frequency) and el2 (second highest).

import java.util.Scanner;

public class SecondHighestOccuringElementBruteForce {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int[] arr=new int[n];
        int max = Integer.MIN_VALUE;
        for(int i=0;i<n;i++) {
            arr[i] = sc.nextInt();
            max = Math.max(max, arr[i]);
        }
        int[] visited=new int[max+1];
        int count = 0;
        int el1Freq=0; int el2Freq=0; int el1=-1; int el2=-1;
        for (int i = 0; i < n ; i++) {
            if(visited[arr[i]]==0){
                visited[arr[i]]=1;
                for (int j = 0; j < n; j++) {
                    if (arr[j] == arr[i]) {
                        count++;
                    }
                }
            }
            if(count > el1Freq){
                el2=el1;
                el2Freq=el1Freq;
                el1=arr[i];
                el1Freq=count;
            }
            else if(count > el2Freq ){
                el2=arr[i];
                el2Freq=count;
            } else if (count == el1Freq && arr[i]<el1) {
                el1=arr[i];
            } else if (count == el2Freq && arr[i]<el2) {
                el2=arr[i];
            }
        }
        System.out.println(el2);
    }
}
1

visited[] skips recounting

Each distinct value runs the inner j loop only once, on its first appearance.

2

Two leader slots

A count bigger than el1Freq pushes the old leader down into el2. A count between the two replaces el2.

3

Ties prefer the smaller value

The last two branches keep the smaller element when a count equals a leader's frequency.

4

-1 means "no second"

el2 starts at -1, which is printed if nothing ever takes second place.

03 Live tracer

This runs exactly the code above, one step at a time. Switch versions to see what each fix changes.

๐ŸŽฌ Frequency tracer
Amber pointer = i, teal pointer = j. The beam turns teal on a match and rose on a mismatch. The row below is visited[]. Click any table row to jump to it.
i
j
arr[]
visited[]
i = –
j = –
count = 0
comparisons = 0
1st · el1 / el1Freq
-1
freq 0
2nd · el2 / el2Freq
-1
freq 0
Load an array, then press Step ▶ to begin.
0 / 00%
Program printed–
Expected answer–
Verdict–
Speed
#ijarr[i]arr[j]Actioncountel1 (freq)el2 (freq)

04 Why it prints the wrong answer

On [1 2 2 3 3 3] the code prints 3 instead of 2, which is the most frequent value, not the second. Three logic bugs work together, and there is one input limit. Each Trace it button loads the tracer at the step where that bug happens.

1

count is never reset

int count = 0; sits outside the loop, so each new value's count is added to the total from earlier values. In [5 5 2], value 2 appears once, but count becomes 3 (2 + 1), so 2 wrongly takes first place.

2

Repeats are re-ranked with a stale count

The el1/el2 comparison sits outside the if(visited…) block, so it also runs for values already seen, using a count left over from earlier. That is how one value can end up in both slots. In [1 2 2 3 3 3], 2 fills both slots, then 3 does the same, and 3 gets printed.

3

A tie for first lands in second place

If count == el1Freq, the check count > el2Freq is usually true too, and it comes first. So a value that ties for first is put in el2, and the count == el1Freq branch below it almost never runs. With bugs 1–2 fixed, [1 1 2 2] prints 2, but both values have the same frequency, so the answer is -1.

4

Limit: negatives and huge values

visited has size max + 1. A negative value throws ArrayIndexOutOfBoundsException at visited[arr[i]], and a value like 10⁹ needs about 4 GB. This isn't a logic bug, but it limits which inputs the approach can handle.

05 The fixed version

Same approach, same variable names. Only the three highlighted parts change. I checked it against the expected answer on 600 random arrays with no mismatches.

import java.util.Scanner;

public class SecondHighestOccuringElementBruteForce {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int[] arr=new int[n];
        int max = Integer.MIN_VALUE;
        for(int i=0;i<n;i++) {
            arr[i] = sc.nextInt();
            max = Math.max(max, arr[i]);
        }
        int[] visited=new int[max+1];
        int el1Freq=0; int el2Freq=0; int el1=-1; int el2=-1;
        for (int i = 0; i < n ; i++) {
            if(visited[arr[i]]==1) continue;    // fix 2: rank each value once
            visited[arr[i]]=1;
            int count = 0;                   // fix 1: fresh count per value
            for (int j = 0; j < n; j++) {
                if (arr[j] == arr[i]) {
                    count++;
                }
            }
            if(count > el1Freq){
                el2=el1;
                el2Freq=el1Freq;
                el1=arr[i];
                el1Freq=count;
            } else if (count == el1Freq) {       // fix 3: tie for 1st checked
                if (arr[i]<el1) el1=arr[i];      //        before 2nd place
            } else if(count > el2Freq){
                el2=arr[i];
                el2Freq=count;
            } else if (count == el2Freq && arr[i]<el2) {
                el2=arr[i];
            }
        }
        System.out.println(el2);
    }
}
Tip: choose Fully fixed in the tracer and load [1 2 2 3 3 3]. Repeated values now skip straight past the ranking, and the program prints 2.

06 Complexity

Let D be the number of distinct values. Because of visited, the inner loop runs only D times, once per distinct value, and each run does N comparisons.

StepCost
Read input, find maxO(N)
Allocate visited[max + 1]O(max)
Count each distinct valueO(D × N)
Total timeO(D × N + max), worst case O(N² + max) when all values are distinct
Extra spaceO(max), not O(1): visited grows with the largest value

You can check this in the tracer: [4 4 4 1 1 2] has D = 3 and N = 6, so it makes exactly 3 × 6 = 18 comparisons. For large inputs, a HashMap<Integer, Integer> of frequencies does the same job in O(N) average time and O(D) space, and it handles negative values.

ApproachTimeExtra spaceNegatives / huge values
Brute force + visitedO(D × N + max)O(max)No
HashMap of frequenciesO(N) avgO(D)Yes

07 Quick revision

1

Reset per-item counters inside the loop

A counter declared outside the loop keeps adding up across iterations.

2

Rank each value exactly once

Put the el1/el2 update inside the first-visit block, or continue on repeats.

3

Check ties before "greater than second"

Branch order matters: count == el1Freq must come before count > el2Freq.

4

Watch for el1 == el2

If both slots hold the same value, something is ranking a value twice.

5

visited costs O(max) space

It grows with the largest value, not with N, and can't handle negative values.

6

Test the tricky inputs

Try all equal [7 7], a tie for first [1 1 2 2], and the mode appearing last [1 2 2 3 3 3].

08 Check yourself

Interactive reference for the "second highest occurring element" pattern in Java-based DSA practice.

Comments

Popular posts from this blog

Get Keycloak Auth Access Token

Understanding Keycloak Auth Access Token – A Deep Dive $ keycloak / auth-deep-dive ๐Ÿ” Identity & Access Management Getting a Keycloak Access Token — and Actually Understanding It June 2025 Keycloak OAuth 2.0 JWT OpenID Connect Service Account You hit Keycloak's token endpoint, you get back a fat JSON blob — but what is all that stuff? This post dismantles a real token response piece by piece so you know exactly what you have, why the JWT is structured the way it is, and what to do with it next. ๐Ÿ“ก Step 1 — How to Get the Token Keycloak speaks OAuth 2.0 . The endpoint that issues tokens lives under your realm: HTTP Token Endpoint POST http://127.0.0.1:7080/realms/master/protocol/openid-connect/token Content-Type : application/x-www-form-urlencoded grant_type =client_credentials &client_id =eazybank-callcenter-cc ...

Observability & Monitoring through Loki,Promtail (Alloy),Prometheus,Micrometer in Grafana

๐Ÿ”ง What this demo covers End-to-end observability setup using Prometheus + Loki + Grafana Integration of Micrometer with Spring Boot for real-time metrics Log collection using Promtail / Alloy from application containers ๐Ÿ“Š Metrics Monitoring (Prometheus) Scraping metrics from /actuator/prometheus endpoint JVM metrics: memory, threads, GC activity HTTP metrics: request count, latency, error rates Custom metrics via Micrometer ๐Ÿ“œ Centralized Logging (Loki + Promtail) Aggregates logs from multiple microservices Label-based log filtering (fast & efficient) No heavy indexing → lightweight compared to ELK ๐Ÿ“ˆ Visualization (Grafana Dashboards) Real-time dashboards for metrics & logs Correlate logs with metrics for faster debugging Pre-built + custom dashboards ⚙️ Architecture Flow Spring Boot app → exposes metrics via Micrometer Prometheus → scrapes & stores metrics Promtail/Alloy → collects logs → pushes to Loki...