In data analysis and statistics, a common initial task is classifying numbers based on their sign. HackerRank's Plus-Minus ratio challenge is a standard test of this concept.

Given an array of integers, we need to calculate the ratio of positive values, negative values, and zero values relative to the total number of elements. The challenge requires printing each ratio on a new line, formatted as a decimal with exactly six decimal places.

While iterating and counting values is basic programming, this problem tests your handling of type casting (to avoid integer truncation) and output formatting. We can solve this cleanly in Java using the Stream API for declaration and custom decimal string formats.

Illustration representing math ratios and double values
Real-World Analogy: The Color-Coded Candy Bag

To visualize this task, imagine a bag containing 6 candies of different colors:

  • 3 Red candies (representing Positive numbers)
  • 2 Blue candies (representing Negative numbers)
  • 1 Green candy (representing Zero)
To calculate the color ratios in the bag, we divide the count of each color by the total:
  • Red Candy Ratio: 3 / 6 = 0.500000 (half of the bag is Red).
  • Blue Candy Ratio: 2 / 6 = 0.333333 (one-third of the bag is Blue).
  • Green Candy Ratio: 1 / 6 = 0.166667 (one-sixth of the bag is Green).
Dividing integers naively in programming causes truncation (for example, 3 / 6 yields 0 in integer division). To prevent this, we must cast the counts to decimal values (such as double or float) before dividing.

Technical Strategy

Our Java strategy consists of two main parts:

  1. Filtering Streams: We use the Stream API to filter elements dynamically:
    • Positive count: arr.stream().filter(n -> n > 0).count()
    • Negative count: arr.stream().filter(n -> n < 0).count()
    • Zero count: arr.stream().filter(n -> n == 0).count()
  2. Decimal Formatting: To satisfy the six-decimal-place requirement, we format the resulting quotient using String.format("%.6f", quotient). The %.6f format specifier tells the JVM to print a floating-point number rounded to exactly six decimal places.

Step-by-Step Scenario Trace

Let's trace the algorithm on an array of size N = 6: arr = [-4, 3, -9, 0, 4, 1]:

  • Positive Count: The values 3, 4, and 1 are greater than zero. Count is 3. Ratio: 3.0 / 6.0 = 0.500000.
  • Negative Count: The values -4 and -9 are less than zero. Count is 2. Ratio: 2.0 / 6.0 = 0.333333.
  • Zero Count: The value 0 is equal to zero. Count is 1. Ratio: 1.0 / 6.0 = 0.166667.
Each value is printed to the console on a separate line.

Java Implementation Code

Below is the complete Java code solving the challenge:

package io.practise.hackerrank;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toList;
 
public class PlusMinusRatio {
    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
 
        int n = Integer.parseInt(bufferedReader.readLine().trim());
        List<Integer> arr = Stream.of(bufferedReader.readLine().replaceAll("\\s+$", "").split(" "))
                .map(Integer::parseInt)
                .collect(toList());
 
        plusMinus(arr);
        bufferedReader.close();
    }
 
    private static void plusMinus(List<Integer> arr) {
        double total = arr.size();
        double countNegative = arr.stream().filter(element -> element < 0).count();
        double countPositive = arr.stream().filter(element -> element > 0).count();
        double countZero     = arr.stream().filter(element -> element == 0).count();
 
        System.out.println(String.format("%.6f", countPositive / total));
        System.out.println(String.format("%.6f", countNegative / total));
        System.out.println(String.format("%.6f", countZero / total));
    }
}

Conclusion & Complexity Analysis

This solution runs in O(N) linear time complexity (as we inspect each array element to classify its sign) and uses O(1) constant space. Utilizing functional streams keeps the logic concise and readable, making it easy to adapt for more complex classification pipelines.