- Overview
- Practice Package (
org.mjtech.pratice) - String Processing Package (
org.mjtech.string) - Number Processing Package (
org.mjtech.number) - Stream API Package (
org.mjtech.stream) - Algorithms Package (
org.mjtech.algorithms) - Design Patterns Package (
org.mjtech.patterns) - Concurrency Package (
org.mjtech.concurrency) - Core Java QA Packages
- Best Practices and Tips
This comprehensive guide covers Java problem-solving approaches across multiple domains, from basic programming concepts to advanced design patterns and concurrency. Each package is organized by specific problem categories with practical examples and multiple solution approaches.
- π’ Beginner: Basic syntax and concepts
- π‘ Intermediate: Algorithmic thinking and data structures
- π΄ Advanced: Complex algorithms, design patterns, and optimization
Problem Statement: Process employee data using various operations like sorting, filtering, and aggregation.
Approach:
// Sample Employee Data
List<Employee> employees = List.of(
new Employee("Jafar", "DEV", 10_000, 26),
new Employee("Karthik", "DEV", 30_000, 29),
new Employee("Ismail", "MAG", 50_000, 30)
);Key Techniques:
- Sorting:
Comparator.comparingDouble(Employee::salary) - Filtering:
stream().filter(emp -> emp.age() > 30) - Grouping:
Collectors.groupingBy(Employee::dept) - Aggregation:
Collectors.averagingDouble(Employee::salary)
Sample Solutions:
- Find Nth highest salary:
sorted().skip(n-1).limit(1) - Department-wise average:
groupingBy(dept, averagingDouble(salary)) - Age-based filtering:
filter(emp -> emp.age() > threshold)
Problem Statement: Find patterns, duplicates, and perform mathematical operations on number arrays.
Approach:
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 10, 8, 9, 10);
// Find second largest (Stream approach)
numbers.stream()
.distinct()
.sorted(Comparator.reverseOrder())
.skip(1)
.limit(1)
.findFirst();
// Traditional approach
int first = Integer.MIN_VALUE, second = Integer.MIN_VALUE;
for (int num : array) {
if (num > first) {
second = first;
first = num;
} else if (num > second && num != first) {
second = num;
}
}Problem Statement: Analyze text for character frequency, word patterns, and text processing.
Key Techniques:
- Character Frequency:
chars().collect(groupingBy(identity(), counting())) - Case Handling:
toLowerCase()for consistent processing - Pattern Matching: Regular expressions for complex patterns
Problem Statement: Work with key-value pairs for ranking, filtering, and transformation.
Sample Code:
Map<String, Integer> languages = Map.of(
"Java", 50, "Python", 150, "JavaScript", 200
);
// Top N languages by score
String topLanguages = languages.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.limit(3)
.map(Map.Entry::getKey)
.collect(Collectors.joining(", "));Problem Statement: Count occurrences of characters in strings with various encoding schemes.
Approaches:
Traditional Method:
Map<Character, Integer> frequencyMap = new HashMap<>();
for (char c : input.toCharArray()) {
frequencyMap.put(c, frequencyMap.getOrDefault(c, 0) + 1);
}Stream API Method:
Map<Character, Long> frequency = input.chars()
.mapToObj(c -> (char) c)
.collect(Collectors.groupingBy(
Function.identity(),
LinkedHashMap::new,
Collectors.counting()
));Problem Statement: Compress strings by representing consecutive identical characters as character + count.
Example: "aaabbccccaa" β "a3b2c4a2"
Implementation:
public static String runLengthEncoding(String input) {
StringBuilder result = new StringBuilder();
int count = 1;
for (int i = 0; i < input.length() - 1; i++) {
if (input.charAt(i) == input.charAt(i + 1)) {
count++;
} else {
result.append(input.charAt(i)).append(count).append(" ");
count = 1;
}
}
result.append(input.charAt(input.length() - 1)).append(count);
return result.toString();
}Problem Statement: Expand compressed strings where numbers indicate repetition count.
Example: "s3m4A4" β "sssmmmAAAA"
Key Techniques:
- Character parsing with
Character.isAlphabetic()andCharacter.isDigit() - Multi-digit number handling
- String repetition with
String.repeat(count)
- Palindrome Detection: Case-insensitive with special character handling
- Anagram Check: Character frequency comparison
- Longest Substring Without Repeating Characters: Sliding window technique
- First Non-Repeating Character: LinkedHashMap for insertion order
Problem Statement: Sort digits within numbers in ascending or descending order.
Multiple Approaches:
Traditional Array Sorting:
public static int sortDigitsAscending(int number) {
char[] digits = String.valueOf(number).toCharArray();
Arrays.sort(digits);
return Integer.parseInt(String.valueOf(digits));
}Stream API Approach:
public static int sortDigitsWithStreams(int number) {
String sorted = String.valueOf(number).chars()
.sorted()
.mapToObj(c -> String.valueOf((char) c))
.collect(Collectors.joining());
return Integer.parseInt(sorted);
}Problem Statement: Extract meaningful information from numbers.
Key Operations:
- Min/Max Digits:
chars().map(Character::getNumericValue).min()/max() - Digit Frequency: Character counting with TreeMap for sorted output
- Unique Digit Check:
distinct().count() == length - Number Reversal: StringBuilder reverse
Problem Statement: Sort and analyze arrays based on number properties.
Advanced Techniques:
// Sort by digit sum
public static int[] sortArrayByDigitSum(int[] numbers) {
return Arrays.stream(numbers)
.boxed()
.sorted(Comparator.comparingInt(NumberSort::calculateDigitSum))
.mapToInt(Integer::intValue)
.toArray();
}
// Calculate digit sum
public static int calculateDigitSum(int number) {
return String.valueOf(Math.abs(number)).chars()
.map(Character::getNumericValue)
.sum();
}Problem Statement: Identify numbers with special mathematical properties.
Implementations:
Armstrong Numbers:
public static boolean isArmstrongNumber(int number) {
String numStr = String.valueOf(number);
int numDigits = numStr.length();
int sum = numStr.chars()
.map(Character::getNumericValue)
.map(digit -> (int) Math.pow(digit, numDigits))
.sum();
return sum == number;
}Perfect Numbers: Sum of proper divisors equals the number Happy Numbers: Digit square sum eventually reaches 1 Prime Numbers: Sieve of Eratosthenes for efficient generation
Focus: Basic stream operations and transformations
Sample Problems:
- Group strings by length
- Find duplicates in collections
- Convert to uppercase
- Filter and sum operations
- Character frequency counting
Key Patterns:
// Grouping pattern
Map<Integer, List<String>> grouped = strings.stream()
.collect(Collectors.groupingBy(String::length));
// Filtering and collecting
List<String> duplicates = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet().stream()
.filter(entry -> entry.getValue() > 1)
.map(Map.Entry::getKey)
.collect(Collectors.toList());Focus: Complex aggregations and multi-step operations
Advanced Patterns:
- Nested Grouping: Department and age-based grouping
- Partitioning: Split data based on predicates
- Custom Collectors: Specialized collection strategies
- Statistical Operations: Average, max, min with grouping
Complex Example:
// Multi-level grouping and aggregation
Map<String, Double> avgSalaryByDept = employees.stream()
.collect(Collectors.groupingBy(
Employee::dept,
Collectors.averagingDouble(Employee::salary)
));Focus: Complex business logic with streams
Advanced Scenarios:
- Moving Averages: Sliding window calculations
- Complex Filtering: Multi-criteria filtering with all/any conditions
- Data Transformation: Flat mapping and complex projections
Essential Problems:
Two Sum Problem:
public static int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
return new int[]{map.get(complement), i};
}
map.put(nums[i], i);
}
return new int[0];
}Maximum Subarray (Kadane's Algorithm):
public static int maxSubarraySum(int[] nums) {
int maxSoFar = nums[0];
int maxEndingHere = nums[0];
for (int i = 1; i < nums.length; i++) {
maxEndingHere = Math.max(nums[i], maxEndingHere + nums[i]);
maxSoFar = Math.max(maxSoFar, maxEndingHere);
}
return maxSoFar;
}Key Concepts:
- Balanced Parentheses: Stack-based validation
- Next Greater Element: Monotonic stack technique
- Queue using Stacks: Dual-stack implementation
Fundamental Algorithms:
Merge Sort Implementation:
- Time Complexity: O(n log n)
- Space Complexity: O(n)
- Stable sorting algorithm
Binary Search:
- Time Complexity: O(log n)
- Prerequisite: Sorted array
Quick Sort:
- Average Time: O(n log n)
- Worst Case: O(nΒ²)
- In-place sorting
Singleton Pattern:
public class DatabaseConnection {
private static volatile DatabaseConnection instance;
private static final Object lock = new Object();
public static DatabaseConnection getInstance() {
if (instance == null) {
synchronized (lock) {
if (instance == null) {
instance = new DatabaseConnection();
}
}
}
return instance;
}
}Builder Pattern:
- Flexible object construction
- Method chaining
- Immutable object creation
Factory Pattern:
- Object creation abstraction
- Type-based instantiation
Adapter Pattern: Interface compatibility Decorator Pattern: Dynamic behavior addition Observer Pattern: Event notification system
Strategy Pattern: Algorithm family encapsulation Command Pattern: Request encapsulation Template Method: Algorithm skeleton definition
Thread Creation and Management:
// Thread creation approaches
Thread thread1 = new Thread(() -> {
// Task implementation
});
// ExecutorService approach
ExecutorService executor = Executors.newFixedThreadPool(3);
Future<Integer> result = executor.submit(() -> {
return computeValue();
});Race Condition Prevention:
- Synchronized methods: Method-level synchronization
- Atomic operations: Lock-free programming
- ReadWrite locks: Concurrent read access
Producer-Consumer Problem:
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
// Producer
queue.put(item); // Blocks if queue is full
// Consumer
int item = queue.take(); // Blocks if queue is emptyDining Philosophers: Deadlock prevention strategies
- Method Overloading: Parameter type resolution
- Employee Processing: Data aggregation patterns
- Singleton Implementation: Thread-safe instantiation
- Character Frequency: Traditional vs Stream approaches
- TreeMap Usage: Sorted output generation
- Incedo: Top N elements selection
- TVS: Duplicate separation algorithms
- J2V: Employee service patterns
-
Stream vs Traditional Loops:
- Streams for readability
- Traditional loops for performance-critical code
-
Memory Management:
- Use appropriate collection sizes
- Consider primitive collections for large datasets
-
Concurrency Best Practices:
- Prefer concurrent collections
- Use thread-safe operations
- Avoid nested locks
- Start with
stringandnumberpackages - Master basic Stream API operations
- Understand fundamental algorithms
- Deep dive into
algorithmspackage - Learn design patterns
- Practice complex Stream operations
- Master concurrency concepts
- Implement custom solutions
- Optimize for performance
- Data Structures: Arrays, Lists, Maps, Sets
- Algorithms: Sorting, searching, dynamic programming
- Object-Oriented Design: SOLID principles, design patterns
- Concurrency: Thread safety, deadlock prevention
- Stream API: Complex transformations and aggregations
- Implement each problem multiple ways
- Analyze time and space complexity
- Practice explaining your approach
- Handle edge cases and error conditions
This guide provides a comprehensive foundation for Java problem-solving across multiple domains. Each package builds upon previous concepts, creating a structured learning path from basic programming to advanced software engineering principles.
- Implement each problem in multiple ways
- Focus on understanding the underlying concepts
- Practice with real-world scenarios
- Contribute additional problems and solutions
- Spring Framework patterns
- Database connectivity and JPA
- RESTful API design
- Microservices architecture
- Performance tuning and profiling
Happy Coding! π