Hey there, code warriors! 👋 Ever found yourself in a prime predicament? Whether you're cracking coding challenges, building cryptographic systems, or just flexing your algorithmic muscles, prime numbers are your trusty sidekicks. And when it comes to finding them efficiently, the Sieve of Eratosthenes is the OG algorithm that's been turning heads since ancient Greece. But wait, there's more! For those massive ranges that make your memory sweat, the Segmented Sieve swoops in like a superhero. 🦸‍♂️

In this article, we're diving deep into both algorithms, spicing things up with some Java magic, and making sure you're ready to tackle primes like a pro. So, grab your favorite beverage, fire up your IDE, and let's get sieving! 🚀

🌟 The Sieve of Eratosthenes: Prime Time Classics
Imagine you're back in 200 BCE, and Eratosthenes, the Greek math wizard, is about to drop the mic with an algorithm so elegant, it’s still cool in 2025. The Sieve of Eratosthenes is all about finding every prime number up to a given limit, and it does it with style and efficiency.

How It Works
Initialize: Create a boolean array isPrime[0..n] and set all entries to true. (Primes are innocent until proven composite!)
Eliminate Non-Primes:
Set isPrime[0] and isPrime[1] to false (they’re not primes).
For each number i from 2 to √n:
If isPrime[i] is true, mark all its multiples as false (they’re composites).
Collect Primes: After the sieving, the indices with true values are your primes. 🎉
Why It’s Awesome
Time Complexity: O(n log log n) – faster than a caffeinated coder on a deadline.
Space Complexity: O(n) – but hey, it’s worth it for all those primes.
Java Code: Sieve in Action
Let’s see this bad boy in Java. Below is a sleek implementation that finds all primes up to a given n.

import java.util.Arrays;

public class SieveOfEratosthenes {
    public static void sieve(int n) {
        boolean[] isPrime = new boolean[n + 1];
        Arrays.fill(isPrime, true);
        isPrime[0] = false;
        isPrime[1] = false;

        for (int i = 2; i * i <= n; i++) {
            if (isPrime[i]) {
                for (int j = i * i; j <= n; j += i) {
                    isPrime[j] = false;
                }
            }
        }

        // Print the primes
        System.out.println("Primes up to " + n + ":");
        for (int i = 2; i <= n; i++) {
            if (isPrime[i]) {
                System.out.print(i + " ");
            }
        }
    }

    public static void main(String[] args) {
        int n = 30;
        sieve(n);  // Output: 2 3 5 7 11 13 17 19 23 29
    }
}

Pro Tip: Notice how we start marking multiples from i * i? That’s because smaller multiples would have already been marked by smaller primes. Efficiency FTW! 🙌

🚀 Segmented Sieve: When Primes Get Too Big for Their Britches
Now, what if you need primes up to, say, a billion? 😱 Your memory might throw a tantrum with the standard sieve. Enter the Segmented Sieve – the cooler, memory-savvy cousin that handles large ranges by breaking them into bite-sized chunks.

Why You Need It
Memory Efficiency: Instead of allocating a giant array for the entire range, you work with smaller segments that fit snugly in memory.
Scalability: Perfect for when n is huge but your RAM isn’t.
How It Works
Find Primes Up to √high: Use the standard sieve to find all primes up to √high (where high is the upper limit of your range). These primes will help us sieve the segments.
Divide and Conquer: Split the range [low, high] into smaller segments. (For simplicity, we’ll sieve the whole range [low, high] in one go here, but the logic extends to multiple segments.)
Sieve Each Segment:
For each segment, initialize a boolean array.
Use the primes from step 1 to mark non-primes in the segment.
Collect Primes: Gather the primes from all segments and bask in their glory. 🌟
Java Code: Segmented Sieve Unleashed
Below is a Java implementation that finds all primes between low and high. For simplicity, we’re handling the range directly, but you can tweak it to process smaller segments for massive ranges.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class SegmentedSieve {
    public static List segmentedSieve(int low, int high) {
        int limit = (int) Math.sqrt(high) + 1;
        boolean[] prime = new boolean[limit + 1];
        Arrays.fill(prime, true);
        prime[0] = prime[1] = false;

        // Find primes up to sqrt(high)
        for (int i = 2; i * i <= limit; i++) {
            if (prime[i]) {
                for (int j = i * i; j <= limit; j += i) {
                    prime[j] = false;
                }
            }
        }

        List primes = new ArrayList<>();
        for (int i = 2; i <= limit; i++) {
            if (prime[i]) {
                primes.add(i);
            }
        }

        // Initialize segment
        boolean[] isPrime = new boolean[high - low + 1];
        Arrays.fill(isPrime, true);

        if (low == 1) {
            isPrime[0] = false;  // 1 is not a prime
        }

        // Sieve the segment using the primes found
        for (int p : primes) {
            int start = Math.max(p * p, (low + p - 1) / p * p);
            for (int j = start; j <= high; j += p) {
                if (j >= low) {
                    isPrime[j - low] = false;
                }
            }
        }

        // Collect primes in the segment
        List result = new ArrayList<>();
        for (int i = low; i <= high; i++) {
            if (isPrime[i - low]) {
                result.add(i);
            }
        }
        return result;
    }

    public static void main(String[] args) {
        int low = 10;
        int high = 50;
        System.out.println("Primes between " + low + " and " + high + ":");
        List primes = segmentedSieve(low, high);
        for (int prime : primes) {
            System.out.print(prime + " ");  // Output: 11 13 17 19 23 29 31 37 41 43 47
        }
    }
}

Cool Insight: By sieving segments, you can handle ranges up to 10^12 or beyond, as long as each segment fits in memory. That’s some serious prime-hunting power! 💪

🎯 When to Use Which?
Sieve of Eratosthenes: Your go-to for finding all primes up to a moderate n (say, up to 10^7). It’s simple, fast, and gets the job done.
Segmented Sieve: When n is enormous (like 10^9 or higher), or when you need primes in a specific range without computing all primes up to that range. It’s memory-efficient and scalable.
🧠 Fun Fact: Primes in the Wild
Did you know that primes are the building blocks of cryptography? Algorithms like RSA rely on the difficulty of factoring large prime products. So, next time you’re securing a connection, give a nod to Eratosthenes! 🔒

🚀 Conclusion: Prime and Ready
Whether you’re battling coding interviews, optimizing algorithms, or just geeking out over numbers, mastering the Sieve of Eratosthenes and its segmented sibling will level up your prime game. With these tools in your Java arsenal, you’re ready to tackle any prime-related challenge that comes your way. So go forth, sieve with style, and may your code always be efficient! 🖥️✨

P.S. Got your own prime tricks or tales? Drop them in the comments below—I’d love to hear how you’re conquering the prime frontier! 🌌