Skip to content

Commit 3f6129f

Browse files
Merge branch 'master' into refactor/InfixToPrefix
2 parents eea751d + acb4753 commit 3f6129f

File tree

9 files changed

+252
-211
lines changed

9 files changed

+252
-211
lines changed

src/main/java/com/thealgorithms/misc/RangeInSortedArray.java

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,46 @@
11
package com.thealgorithms.misc;
22

3+
/**
4+
* Utility class for operations to find the range of occurrences of a key
5+
* in a sorted (non-decreasing) array, and to count elements less than or equal to a given key.
6+
*/
37
public final class RangeInSortedArray {
8+
49
private RangeInSortedArray() {
510
}
611

7-
// Get the 1st and last occurrence index of a number 'key' in a non-decreasing array 'nums'
8-
// Gives [-1, -1] in case element doesn't exist in array
12+
/**
13+
* Finds the first and last occurrence indices of the key in a sorted array.
14+
*
15+
* @param nums sorted array of integers (non-decreasing order)
16+
* @param key the target value to search for
17+
* @return int array of size two where
18+
* - index 0 is the first occurrence of key,
19+
* - index 1 is the last occurrence of key,
20+
* or [-1, -1] if the key does not exist in the array.
21+
*/
922
public static int[] sortedRange(int[] nums, int key) {
1023
int[] range = new int[] {-1, -1};
11-
alteredBinSearchIter(nums, key, 0, nums.length - 1, range, true);
12-
alteredBinSearchIter(nums, key, 0, nums.length - 1, range, false);
24+
alteredBinSearchIter(nums, key, 0, nums.length - 1, range, true); // find left boundary
25+
alteredBinSearchIter(nums, key, 0, nums.length - 1, range, false); // find right boundary
1326
return range;
1427
}
1528

16-
// Recursive altered binary search which searches for leftmost as well as rightmost occurrence
17-
// of 'key'
29+
/**
30+
* Recursive altered binary search to find either the leftmost or rightmost occurrence of a key.
31+
*
32+
* @param nums the sorted array
33+
* @param key the target to find
34+
* @param left current left bound in search
35+
* @param right current right bound in search
36+
* @param range array to update with boundaries: range[0] for leftmost, range[1] for rightmost
37+
* @param goLeft if true, searches for leftmost occurrence; if false, for rightmost occurrence
38+
*/
1839
public static void alteredBinSearch(int[] nums, int key, int left, int right, int[] range, boolean goLeft) {
1940
if (left > right) {
2041
return;
2142
}
22-
int mid = (left + right) >>> 1;
43+
int mid = left + ((right - left) >>> 1);
2344
if (nums[mid] > key) {
2445
alteredBinSearch(nums, key, left, mid - 1, range, goLeft);
2546
} else if (nums[mid] < key) {
@@ -41,11 +62,19 @@ public static void alteredBinSearch(int[] nums, int key, int left, int right, in
4162
}
4263
}
4364

44-
// Iterative altered binary search which searches for leftmost as well as rightmost occurrence
45-
// of 'key'
65+
/**
66+
* Iterative altered binary search to find either the leftmost or rightmost occurrence of a key.
67+
*
68+
* @param nums the sorted array
69+
* @param key the target to find
70+
* @param left initial left bound
71+
* @param right initial right bound
72+
* @param range array to update with boundaries: range[0] for leftmost, range[1] for rightmost
73+
* @param goLeft if true, searches for leftmost occurrence; if false, for rightmost occurrence
74+
*/
4675
public static void alteredBinSearchIter(int[] nums, int key, int left, int right, int[] range, boolean goLeft) {
4776
while (left <= right) {
48-
final int mid = (left + right) >>> 1;
77+
int mid = left + ((right - left) >>> 1);
4978
if (nums[mid] > key) {
5079
right = mid - 1;
5180
} else if (nums[mid] < key) {
@@ -55,33 +84,48 @@ public static void alteredBinSearchIter(int[] nums, int key, int left, int right
5584
if (mid == 0 || nums[mid - 1] != key) {
5685
range[0] = mid;
5786
return;
58-
} else {
59-
right = mid - 1;
6087
}
88+
right = mid - 1;
6189
} else {
6290
if (mid == nums.length - 1 || nums[mid + 1] != key) {
6391
range[1] = mid;
6492
return;
65-
} else {
66-
left = mid + 1;
6793
}
94+
left = mid + 1;
6895
}
6996
}
7097
}
7198
}
7299

100+
/**
101+
* Counts the number of elements strictly less than the given key.
102+
*
103+
* @param nums sorted array
104+
* @param key the key to compare
105+
* @return the count of elements less than the key
106+
*/
73107
public static int getCountLessThan(int[] nums, int key) {
74108
return getLessThan(nums, key, 0, nums.length - 1);
75109
}
76110

111+
/**
112+
* Helper method using binary search to count elements less than or equal to the key.
113+
*
114+
* @param nums sorted array
115+
* @param key the key to compare
116+
* @param left current left bound
117+
* @param right current right bound
118+
* @return count of elements less than or equal to the key
119+
*/
77120
public static int getLessThan(int[] nums, int key, int left, int right) {
78121
int count = 0;
79122
while (left <= right) {
80-
final int mid = (left + right) >>> 1;
123+
int mid = left + ((right - left) >>> 1);
81124
if (nums[mid] > key) {
82125
right = mid - 1;
83-
} else if (nums[mid] <= key) {
84-
count = mid + 1; // At least mid+1 elements exist which are <= key
126+
} else {
127+
// nums[mid] <= key
128+
count = mid + 1; // all elements from 0 to mid inclusive are <= key
85129
left = mid + 1;
86130
}
87131
}

src/main/java/com/thealgorithms/stacks/InfixToPostfix.java

Lines changed: 71 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,54 +4,96 @@
44
import java.util.regex.Matcher;
55
import java.util.regex.Pattern;
66

7+
/**
8+
* Utility class for converting an infix arithmetic expression
9+
* into its equivalent postfix (Reverse Polish Notation) form.
10+
* <p>
11+
* This class provides a static method to perform the conversion,
12+
* validating balanced brackets before processing.
13+
* </p>
14+
*/
715
public final class InfixToPostfix {
16+
817
private InfixToPostfix() {
918
}
1019

11-
public static String infix2PostFix(String infixExpression) throws Exception {
20+
/**
21+
* Converts a given infix expression string to a postfix expression string.
22+
* <p>
23+
* The method first checks if the brackets in the input expression are balanced
24+
* by calling {@code BalancedBrackets.isBalanced} on the filtered brackets.
25+
* If the brackets are not balanced, it throws an IllegalArgumentException.
26+
* </p>
27+
* <p>
28+
* Supported operators are: {@code +, -, *, /, ^}
29+
* and operands can be letters or digits.
30+
* </p>
31+
*
32+
* @param infixExpression the arithmetic expression in infix notation
33+
* @return the equivalent postfix notation expression
34+
* @throws IllegalArgumentException if the brackets in the expression are unbalanced
35+
*/
36+
public static String infix2PostFix(String infixExpression) {
1237
if (!BalancedBrackets.isBalanced(filterBrackets(infixExpression))) {
13-
throw new Exception("invalid expression");
38+
throw new IllegalArgumentException("Invalid expression: unbalanced brackets.");
1439
}
40+
1541
StringBuilder output = new StringBuilder();
16-
Stack<Character> stack = new Stack<>();
17-
for (char element : infixExpression.toCharArray()) {
18-
if (Character.isLetterOrDigit(element)) {
19-
output.append(element);
20-
} else if (element == '(') {
21-
stack.push(element);
22-
} else if (element == ')') {
23-
while (!stack.isEmpty() && stack.peek() != '(') {
24-
output.append(stack.pop());
42+
Stack<Character> operatorStack = new Stack<>();
43+
44+
for (char token : infixExpression.toCharArray()) {
45+
if (Character.isLetterOrDigit(token)) {
46+
// Append operands (letters or digits) directly to output
47+
output.append(token);
48+
} else if (token == '(') {
49+
// Push '(' to stack
50+
operatorStack.push(token);
51+
} else if (token == ')') {
52+
// Pop and append until '(' is found
53+
while (!operatorStack.isEmpty() && operatorStack.peek() != '(') {
54+
output.append(operatorStack.pop());
2555
}
26-
stack.pop();
56+
operatorStack.pop(); // Remove '(' from stack
2757
} else {
28-
while (!stack.isEmpty() && precedence(element) <= precedence(stack.peek())) {
29-
output.append(stack.pop());
58+
// Pop operators with higher or equal precedence and append them
59+
while (!operatorStack.isEmpty() && precedence(token) <= precedence(operatorStack.peek())) {
60+
output.append(operatorStack.pop());
3061
}
31-
stack.push(element);
62+
operatorStack.push(token);
3263
}
3364
}
34-
while (!stack.isEmpty()) {
35-
output.append(stack.pop());
65+
66+
// Pop any remaining operators
67+
while (!operatorStack.isEmpty()) {
68+
output.append(operatorStack.pop());
3669
}
70+
3771
return output.toString();
3872
}
3973

74+
/**
75+
* Returns the precedence level of the given operator.
76+
*
77+
* @param operator the operator character (e.g., '+', '-', '*', '/', '^')
78+
* @return the precedence value: higher means higher precedence,
79+
* or -1 if the character is not a recognized operator
80+
*/
4081
private static int precedence(char operator) {
41-
switch (operator) {
42-
case '+':
43-
case '-':
44-
return 0;
45-
case '*':
46-
case '/':
47-
return 1;
48-
case '^':
49-
return 2;
50-
default:
51-
return -1;
52-
}
82+
return switch (operator) {
83+
case '+', '-' -> 0;
84+
case '*', '/' -> 1;
85+
case '^' -> 2;
86+
default -> -1;
87+
};
5388
}
5489

90+
/**
91+
* Extracts only the bracket characters from the input string.
92+
* Supports parentheses (), curly braces {}, square brackets [], and angle brackets &lt;&gt;.
93+
*
94+
* @param input the original expression string
95+
* @return a string containing only bracket characters from the input
96+
*/
5597
private static String filterBrackets(String input) {
5698
Pattern pattern = Pattern.compile("[^(){}\\[\\]<>]");
5799
Matcher matcher = pattern.matcher(input);

src/main/java/com/thealgorithms/stacks/LargestRectangle.java

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,50 @@
33
import java.util.Stack;
44

55
/**
6+
* Utility class to calculate the largest rectangle area in a histogram.
7+
* Each bar's width is assumed to be 1 unit.
68
*
7-
* @author mohd rameez github.com/rameez471
9+
* <p>This implementation uses a monotonic stack to efficiently calculate
10+
* the area of the largest rectangle that can be formed from the histogram bars.</p>
11+
*
12+
* <p>Example usage:
13+
* <pre>{@code
14+
* int[] heights = {2, 1, 5, 6, 2, 3};
15+
* String area = LargestRectangle.largestRectangleHistogram(heights);
16+
* // area is "10"
17+
* }</pre>
818
*/
9-
1019
public final class LargestRectangle {
20+
1121
private LargestRectangle() {
1222
}
1323

24+
/**
25+
* Calculates the largest rectangle area in the given histogram.
26+
*
27+
* @param heights an array of non-negative integers representing bar heights
28+
* @return the largest rectangle area as a {@link String}
29+
*/
1430
public static String largestRectangleHistogram(int[] heights) {
15-
int n = heights.length;
1631
int maxArea = 0;
17-
Stack<int[]> st = new Stack<>();
18-
for (int i = 0; i < n; i++) {
32+
Stack<int[]> stack = new Stack<>();
33+
34+
for (int i = 0; i < heights.length; i++) {
1935
int start = i;
20-
while (!st.isEmpty() && st.peek()[1] > heights[i]) {
21-
int[] tmp = st.pop();
22-
maxArea = Math.max(maxArea, tmp[1] * (i - tmp[0]));
23-
start = tmp[0];
36+
while (!stack.isEmpty() && stack.peek()[1] > heights[i]) {
37+
int[] popped = stack.pop();
38+
maxArea = Math.max(maxArea, popped[1] * (i - popped[0]));
39+
start = popped[0];
2440
}
25-
st.push(new int[] {start, heights[i]});
41+
stack.push(new int[] {start, heights[i]});
2642
}
27-
while (!st.isEmpty()) {
28-
int[] tmp = st.pop();
29-
maxArea = Math.max(maxArea, tmp[1] * (n - tmp[0]));
43+
44+
int totalLength = heights.length;
45+
while (!stack.isEmpty()) {
46+
int[] remaining = stack.pop();
47+
maxArea = Math.max(maxArea, remaining[1] * (totalLength - remaining[0]));
3048
}
31-
return Integer.toString(maxArea);
32-
}
3349

34-
public static void main(String[] args) {
35-
assert largestRectangleHistogram(new int[] {2, 1, 5, 6, 2, 3}).equals("10");
36-
assert largestRectangleHistogram(new int[] {2, 4}).equals("4");
50+
return Integer.toString(maxArea);
3751
}
3852
}

src/main/java/com/thealgorithms/strings/Isomorphic.java

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,54 @@
55
import java.util.Map;
66
import java.util.Set;
77

8+
/**
9+
* Utility class to check if two strings are isomorphic.
10+
*
11+
* <p>
12+
* Two strings {@code s} and {@code t} are isomorphic if the characters in {@code s}
13+
* can be replaced to get {@code t}, while preserving the order of characters.
14+
* Each character must map to exactly one character, and no two characters can map to the same character.
15+
* </p>
16+
*
17+
* @see <a href="https://en.wikipedia.org/wiki/Isomorphism_(computer_science)">Isomorphic Strings</a>
18+
*/
819
public final class Isomorphic {
20+
921
private Isomorphic() {
1022
}
1123

12-
public static boolean checkStrings(String s, String t) {
24+
/**
25+
* Checks if two strings are isomorphic.
26+
*
27+
* @param s the first input string
28+
* @param t the second input string
29+
* @return {@code true} if {@code s} and {@code t} are isomorphic; {@code false} otherwise
30+
*/
31+
public static boolean areIsomorphic(String s, String t) {
1332
if (s.length() != t.length()) {
1433
return false;
1534
}
1635

17-
// To mark the characters of string using MAP
18-
// character of first string as KEY and another as VALUE
19-
// now check occurence by keeping the track with SET data structure
20-
Map<Character, Character> characterMap = new HashMap<>();
21-
Set<Character> trackUniqueCharacter = new HashSet<>();
36+
Map<Character, Character> map = new HashMap<>();
37+
Set<Character> usedCharacters = new HashSet<>();
2238

2339
for (int i = 0; i < s.length(); i++) {
24-
if (characterMap.containsKey(s.charAt(i))) {
25-
if (t.charAt(i) != characterMap.get(s.charAt(i))) {
40+
char sourceChar = s.charAt(i);
41+
char targetChar = t.charAt(i);
42+
43+
if (map.containsKey(sourceChar)) {
44+
if (map.get(sourceChar) != targetChar) {
2645
return false;
2746
}
2847
} else {
29-
if (trackUniqueCharacter.contains(t.charAt(i))) {
48+
if (usedCharacters.contains(targetChar)) {
3049
return false;
3150
}
32-
33-
characterMap.put(s.charAt(i), t.charAt(i));
51+
map.put(sourceChar, targetChar);
52+
usedCharacters.add(targetChar);
3453
}
35-
trackUniqueCharacter.add(t.charAt(i));
3654
}
55+
3756
return true;
3857
}
3958
}

0 commit comments

Comments
 (0)