Definition
- Linear scan – visit every element because the target can appear anywhere, giving O(n) time.
- Counter variable – a single
int counttracks matches, giving O(1) extra space. - No early exit – unlike existence checks, counting requires inspecting every element.
- Value equality – for
BigDecimalusecompareToreturning zero, notequals, becauseequalsalso checks scale. - Result – the counter holds the total number of occurrences when the loop ends.
Rajesh wants to know how many times exactly Rs.5000 was debited from his account SAV2001 this month, perhaps a recurring subscription. He reads each transaction in his passbook, and every time the amount is exactly Rs.5000 he makes a tally mark. At the end, the number of tally marks is the count.
Understanding the Concepts
What is the problem?
Given an array and a target value, count how many times the target appears. In a banking context, Rajesh wants to detect how many times a recurring Rs.5000 subscription was charged to his savings account SAV2001 at National Bank of India this month.
How does the algorithm work?
Start a counter at zero. Loop through every element and compare it with the target. If they match, increment the counter. There is no early exit because the same value can appear at any position.
package com.bank.service;
import java.math.BigDecimal;
public class RecurringChargeDetector {
public static int countOccurrences(BigDecimal[] amounts, BigDecimal target) {
if (amounts == null) {
throw new IllegalArgumentException("Amounts array cannot be null");
}
int count = 0;
for (BigDecimal amount : amounts) {
if (target.compareTo(amount) == 0) {
count++;
}
}
return count;
}
public static void main(String[] args) {
BigDecimal[] transactions = {
new BigDecimal("5000.00"),
new BigDecimal("12500.00"),
new BigDecimal("5000"),
new BigDecimal("8700.50"),
new BigDecimal("5000.00"),
new BigDecimal("3200.00")
};
BigDecimal target = new BigDecimal("5000");
int count = countOccurrences(transactions, target);
System.out.println("Rs.5000 charged " + count + " times this month");
}
}
Rs.5000 charged 3 times this month
Why use compareTo instead of equals for BigDecimal?
BigDecimal's equals method checks both numeric value and scale. So new BigDecimal("5000") and new BigDecimal("5000.00") are NOT equal under equals because their scales differ (0 vs 2). Using compareTo returning zero treats both as the same amount, which is what a bank customer expects.
BigDecimal a = new BigDecimal("5000");
BigDecimal b = new BigDecimal("5000.00");
System.out.println(a.equals(b)); // false (scale differs)
System.out.println(a.compareTo(b) == 0); // true (same numeric value)
Why is there no early exit?
Unlike an existence check that can stop at the first match, counting must inspect every element because the target might appear again later. The worst case and the best case are both O(n).
What is the time and space complexity?
- Time: O(n) because every element is visited once.
- Space: O(1) because only a single counter variable is used.
What about sorted arrays?
If the array is sorted, you can find the first occurrence with binary search and the last occurrence with another binary search, then compute the count as lastIndex - firstIndex + 1. This gives O(log n) time instead of O(n), which is a significant improvement for large arrays that are already sorted.
// For a sorted array, binary search approach
// firstIndex = lower bound of target
// lastIndex = upper bound of target
// count = lastIndex - firstIndex + 1
What are common mistakes?
The most common mistake is using equals instead of compareTo for BigDecimal, which misses matches where the scale differs. Another mistake is using == for object comparison, which compares references, not values.
// Wrong: reference comparison
if (amounts[i] == target) { count++; } // compares memory addresses
// Wrong: equals checks scale
if (amounts[i].equals(target)) { count++; } // misses scale-different matches
// Correct: value comparison
if (amounts[i].compareTo(target) == 0) { count++; }
How does this extend to frequency counting?
Counting occurrences of a single value is the building block for frequency histograms. To count occurrences of every distinct value, you can use a HashMap where the key is the amount (normalized with stripTrailingZeros) and the value is the count. This takes one pass and O(k) space where k is the number of distinct values.
import java.util.HashMap;
import java.util.Map;
Map<BigDecimal, Integer> frequency = new HashMap<>();
for (BigDecimal amount : amounts) {
BigDecimal key = amount.stripTrailingZeros();
frequency.merge(key, 1, Integer::sum);
}
What should a senior engineer know?
A senior engineer normalises BigDecimal keys with stripTrailingZeros() before putting them in a HashMap, because HashMap uses equals and hashCode internally, and two BigDecimal values with different scales have different hash codes even if they represent the same number. Without normalisation, the frequency map would treat Rs.5000 and Rs.5000.00 as separate entries.
Visual Overview
target = 5000
amounts[]: 5000.00 12500 5000 8700.50 5000.00 3200
│
▼
count = 0
┌──────────────────────────────────────────────┐
│ 5000.00 compareTo 5000 == 0? YES → count=1 │
│ 12500 compareTo 5000 == 0? NO │
│ 5000 compareTo 5000 == 0? YES → count=2 │
│ 8700.50 compareTo 5000 == 0? NO │
│ 5000.00 compareTo 5000 == 0? YES → count=3 │
│ 3200 compareTo 5000 == 0? NO │
└──────────────────────────────────────────────┘
Result: count = 3
Key Takeaway
Counting how many times a value appears in an array is a straightforward linear scan with a counter. I start a counter at zero, loop through every element, and increment the counter each time the element matches the target. There is no early exit because the target can appear anywhere, so I must inspect every element.
In my banking project at National Bank of India, I used this to build a recurring charge detector. Rajesh wanted to know how many times exactly five thousand rupees was debited this month so he could spot a subscription he forgot about. I loop through his transaction amounts and tally each one that equals five thousand.
The important nuance here is how I compare money. I compare BigDecimal values using the compareTo method and check for a result of zero, rather than using the equals method. The reason is that five thousand written as plain five thousand and five thousand written with two decimal places are the same amount of money, but the equals method considers them different because their scale differs. By using compareTo I treat them as equal in value, which is exactly what the customer means.
Remember one sentence: walk every element, compare with compareTo for BigDecimal, and increment the counter on each match.
---