Posted on: March 12, 2025 Posted by: rahulgite Comments: 0
import java.util.*;
import java.util.stream.Collectors;

public class RepeatedNumbers {
    public static void main(String[] args) {
        int[] arr = {1, 2, 2, 3, 3, 3, 4, 5, 5};

        System.out.println("Using Streams:");
        countRepeatedWithStreams(arr);

        System.out.println("\nWithout Using Streams:");
        countRepeatedWithoutStreams(arr);

        System.out.println("\nOptimized for Sorted Array:");
        countRepeatedInSortedArray(arr);
    }

    // 1. Using Java Streams
    // Approach: 
    // - Convert array to a stream of Integer values.
    // - Use groupingBy to calculate frequency of each number.
    // - Filter entries with a count greater than 1 (repeated numbers).
    // - Count the number of repeated numbers.
    // Time Complexity: O(n) - One pass for grouping, one for filtering.
    // Space Complexity: O(n) - Space required for the frequency map.
    private static void countRepeatedWithStreams(int[] arr) {
        Map<Integer, Long> frequencyMap = Arrays.stream(arr)
                .boxed()
                .collect(Collectors.groupingBy(n -> n, Collectors.counting()));

        long repeatedCount = frequencyMap.values().stream()
                .filter(count -> count > 1)
                .count();

        System.out.println("Total repeated numbers: " + repeatedCount);
    }

    // 2. Without Using Streams
    // Approach: 
    // - Traverse the array and store frequencies in a HashMap.
    // - Iterate over the map and count entries with frequency > 1.
    // Time Complexity: O(n) - Two passes (one for map, one for counting).
    // Space Complexity: O(n) - Space required for the frequency map.
    private static void countRepeatedWithoutStreams(int[] arr) {
        Map<Integer, Integer> frequencyMap = new HashMap<>();
        for (int num : arr) {
            frequencyMap.put(num, frequencyMap.getOrDefault(num, 0) + 1);
        }

        int repeatedCount = 0;
        for (int count : frequencyMap.values()) {
            if (count > 1) repeatedCount++;
        }

        System.out.println("Total repeated numbers: " + repeatedCount);
    }

    // 3. Optimized Approach (If Input is Sorted)
    // Approach:
    // - Use a two-pointer approach to find duplicate ranges.
    // - Increment the repeated count for every range with length > 1.
    // Time Complexity: O(n) - Single pass through the array.
    // Space Complexity: O(1) - No additional space required.
    private static void countRepeatedInSortedArray(int[] arr) {
        int repeatedCount = 0;
        int i = 0;

        while (i < arr.length) {
            int j = i;
            while (j < arr.length && arr[j] == arr[i]) {
                j++;
            }
            if (j - i > 1) repeatedCount++;  // Check if number repeats
            i = j; // Move to next unique number
        }

        System.out.println("Total repeated numbers: " + repeatedCount);
    }
}

/*
Output:
Using Streams:
Total repeated numbers: 3

Without Using Streams:
Total repeated numbers: 3

Optimized for Sorted Array:
Total repeated numbers: 3

Explanation:
- The program implements three different approaches to count how many numbers are repeated in an array.
- It handles both unsorted and sorted arrays efficiently.

Approach Summary:
1. Using Streams: Leverages Java Streams for functional-style processing.
2. Without Streams: Uses traditional iteration and a HashMap.
3. Optimized for Sorted Arrays: Uses a two-pointer technique with O(1) space.

Complexities:
1. Using Streams: O(n) time, O(n) space.
2. Without Streams: O(n) time, O(n) space.
3. Optimized for Sorted Array: O(n) time, O(1) space.
*/

Leave a Comment