Java Generics to Code Efficiently in Competitive Programming

Java Generics is a concept which can be used effectively in competitive programming for writing optimal and reusable code. Generics enable you to declare classes or interfaces, as well as methods with parameters of the type that can be then substituted with concrete types during the instantiation or invoking.

Commonly used functions in Competitive Programming

1. Pairs in Java

A pair is common data type used while programming that simply contains two values connected together. In Java, although there is no inbuilt Pair class in the standard library despite Java being an object oriented language, making and using the pairs is easy and very handy in competitive programming.

Filename: Pairs.java

Output:

(Cherry, 1)
(Banana, 2)
(Apple, 3)

2. Fast Exponential using Modulo

Direct computation of large powers can lead to overflow and is computationally expensive. Fast exponentiation (also known as exponentiation by squaring) is a method to compute powers quickly with a time complexity of O(logn). When combined with modulo operation, it becomes particularly useful for problems involving large numbers.

Filename: FastExponentiation.java

Output:

Result 1: 1024
Result 2: 430973056
Result 3: 889009735

3. Calculating nCr Using Fermat's Little Theorem

In competitive programming, computing combinations (nCr) efficiently is crucial, especially when dealing with large numbers and modulo operations. Fermat's Little Theorem provides an elegant way to handle this efficiently.

Filename: CombinationsUsingFermat.java

Output:

Result 1: 45
Result 2: 4845

4. Binomial Coefficient (Iterative)

The binomial coefficient, represents the number of ways to choose k elements from a set of n elements without regard to the order of selection. It is a fundamental concept in combinatorics and has applications in probability, statistics, and various fields of mathematics.

Filename: BinomialCoefficient.java

Output:

Binomial Coefficient C(5, 2) = 10
Binomial Coefficient C(10, 3) = 120
Binomial Coefficient C(50, 25) = 126410606437752

5. Modular Arithmetic

Modular arithmetic is a system of arithmetic for integers, where numbers "wrap around" upon reaching a certain value called the modulus. Given a positive integer n, called the modulus, two integers a and b are said to be congruent modulo n if their difference a-b is an integer multiple of n. The relationship is written as: a≡b(modn). It means that when a is divided by n, it leaves the same remainder as when b is divided by n.

Filename: ModularArithmetic.java

Output:

Modular Addition: 999999993
Modular Subtraction: 0
Modular Multiplication: 49
Modular Exponentiation: 1024
Modular Inverse: 333333336

6. Sorting an Array

Sorting is a fundamental operation in computer science, widely used to arrange elements in a specific order, such as ascending or descending. Java provides built-in methods to sort arrays and collections efficiently. The primary methods are Arrays.sort() for arrays and Collections.sort() for collections.

Filename: SortExample.java

Output:

Sorted array (primitive types): [1, 2, 3, 5, 7, 8]
Sorted array (objects): [Alice, Bob, Charlie]
Custom sorted array by length: [Bob, Alice, Charlie]
Sorted list (primitive types): [1, 2, 3, 5, 7, 8]
Custom sorted list by length: [Bob, Alice, Charlie]

7. GCD and LCM

The Greatest Common Divisor (GCD) of two integers is the largest positive integer that divides both numbers without leaving a remainder. The Least Common Multiple (LCM) of two integers is the smallest positive integer that is divisible by both numbers. The product of two numbers is equal to the product of their GCD and LCM: LCM(a,b)×GCD(a,b)=a×b.

Filename: GcdLcmExample.java

Output:

GCD of 24 and 36 is: 12
LCM of 24 and 36 is: 72

8. Optimizing Nested Loops

Nested loops are common in competitive programming, especially when searching for combinations or pairs that satisfy certain conditions, such as finding pairs in an array that sum up to a specific value.

Filename: PairSumOptimized.java

Output:

Pairs with sum 16: (10, 6

Benefits of Using Generics

1. Faster Execution

Efficient algorithms and data structures often lead to faster execution times, crucial in competitive programming where speed can determine rankings.

2. Problem-solving Flexibility

Tricks and optimizations provide multiple approaches to solve a problem, giving flexibility to choose the most suitable method based on constraints or requirements.

3. Competitive Advantage

In competitive programming, where time and correctness are crucial, using efficient tricks can give an edge over competitors by solving problems faster or handling edge cases effectively.