Skip to content

Commit 3c55907

Browse files
authored
Merge branch 'master' into feat
2 parents c0bd318 + 9484c7e commit 3c55907

35 files changed

+2728
-16
lines changed

DIRECTORY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
- 📄 [AnyBaseToAnyBase](src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java)
9595
- 📄 [AnyBaseToDecimal](src/main/java/com/thealgorithms/conversions/AnyBaseToDecimal.java)
9696
- 📄 [AnytoAny](src/main/java/com/thealgorithms/conversions/AnytoAny.java)
97+
- 📄 [Base64](src/main/java/com/thealgorithms/conversions/Base64.java)
9798
- 📄 [BinaryToDecimal](src/main/java/com/thealgorithms/conversions/BinaryToDecimal.java)
9899
- 📄 [BinaryToHexadecimal](src/main/java/com/thealgorithms/conversions/BinaryToHexadecimal.java)
99100
- 📄 [BinaryToOctal](src/main/java/com/thealgorithms/conversions/BinaryToOctal.java)
@@ -839,6 +840,7 @@
839840
- 📄 [AffineConverterTest](src/test/java/com/thealgorithms/conversions/AffineConverterTest.java)
840841
- 📄 [AnyBaseToDecimalTest](src/test/java/com/thealgorithms/conversions/AnyBaseToDecimalTest.java)
841842
- 📄 [AnytoAnyTest](src/test/java/com/thealgorithms/conversions/AnytoAnyTest.java)
843+
- 📄 [Base64Test](src/test/java/com/thealgorithms/conversions/Base64Test.java)
842844
- 📄 [BinaryToDecimalTest](src/test/java/com/thealgorithms/conversions/BinaryToDecimalTest.java)
843845
- 📄 [BinaryToHexadecimalTest](src/test/java/com/thealgorithms/conversions/BinaryToHexadecimalTest.java)
844846
- 📄 [BinaryToOctalTest](src/test/java/com/thealgorithms/conversions/BinaryToOctalTest.java)

pom.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,7 @@
7171
<artifactId>maven-compiler-plugin</artifactId>
7272
<version>3.14.1</version>
7373
<configuration>
74-
<source>21</source>
75-
<target>21</target>
74+
<release>21</release>
7675
<compilerArgs>
7776
<arg>-Xlint:all</arg>
7877
<arg>-Xlint:-auxiliaryclass</arg>

spotbugs-exclude.xml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,6 @@
8080
<Match>
8181
<Bug pattern="SA_FIELD_SELF_ASSIGNMENT" />
8282
</Match>
83-
<Match>
84-
<Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE" />
85-
</Match>
8683
<Match>
8784
<Bug pattern="AT_STALE_THREAD_WRITE_OF_PRIMITIVE" />
8885
</Match>

src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@ private BitSwap() {
1717
* @return The modified value with swapped bits
1818
* @throws IllegalArgumentException if either position is negative or ≥ 32
1919
*/
20+
2021
public static int bitSwap(int data, final int posA, final int posB) {
2122
if (posA < 0 || posA >= Integer.SIZE || posB < 0 || posB >= Integer.SIZE) {
2223
throw new IllegalArgumentException("Bit positions must be between 0 and 31");
2324
}
2425

25-
if (SingleBitOperations.getBit(data, posA) != SingleBitOperations.getBit(data, posB)) {
26+
boolean bitA = ((data >> posA) & 1) != 0;
27+
boolean bitB = ((data >> posB) & 1) != 0;
28+
if (bitA != bitB) {
2629
data ^= (1 << posA) ^ (1 << posB);
2730
}
2831
return data;
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.thealgorithms.bitmanipulation;
2+
3+
/**
4+
* Implementation to count number of bits to be flipped to convert A to B
5+
*
6+
* Problem: Given two numbers A and B, count the number of bits needed to be
7+
* flipped to convert A to B.
8+
*
9+
* Example:
10+
* A = 10 (01010 in binary)
11+
* B = 20 (10100 in binary)
12+
* XOR = 30 (11110 in binary) - positions where bits differ
13+
* Answer: 4 bits need to be flipped
14+
*
15+
* Time Complexity: O(log n) - where n is the number of set bits
16+
* Space Complexity: O(1)
17+
*
18+
*@author [Yash Rajput](https://github.com/the-yash-rajput)
19+
*/
20+
public final class CountBitsFlip {
21+
22+
private CountBitsFlip() {
23+
throw new AssertionError("No instances.");
24+
}
25+
26+
/**
27+
* Counts the number of bits that need to be flipped to convert a to b
28+
*
29+
* Algorithm:
30+
* 1. XOR a and b to get positions where bits differ
31+
* 2. Count the number of set bits in the XOR result
32+
* 3. Use Brian Kernighan's algorithm: n & (n-1) removes rightmost set bit
33+
*
34+
* @param a the source number
35+
* @param b the target number
36+
* @return the number of bits to flip to convert A to B
37+
*/
38+
public static long countBitsFlip(long a, long b) {
39+
int count = 0;
40+
41+
// XOR gives us positions where bits differ
42+
long xorResult = a ^ b;
43+
44+
// Count set bits using Brian Kernighan's algorithm
45+
while (xorResult != 0) {
46+
xorResult = xorResult & (xorResult - 1); // Remove rightmost set bit
47+
count++;
48+
}
49+
50+
return count;
51+
}
52+
53+
/**
54+
* Alternative implementation using Long.bitCount().
55+
*
56+
* @param a the source number
57+
* @param b the target number
58+
* @return the number of bits to flip to convert a to b
59+
*/
60+
public static long countBitsFlipAlternative(long a, long b) {
61+
return Long.bitCount(a ^ b);
62+
}
63+
}
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package com.thealgorithms.conversions;
2+
3+
import java.nio.charset.StandardCharsets;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
7+
/**
8+
* Base64 is a group of binary-to-text encoding schemes that represent binary data
9+
* in an ASCII string format by translating it into a radix-64 representation.
10+
* Each base64 digit represents exactly 6 bits of data.
11+
*
12+
* Base64 encoding is commonly used when there is a need to encode binary data
13+
* that needs to be stored and transferred over media that are designed to deal
14+
* with textual data.
15+
*
16+
* Wikipedia Reference: https://en.wikipedia.org/wiki/Base64
17+
* Author: Nithin U.
18+
* Github: https://github.com/NithinU2802
19+
*/
20+
21+
public final class Base64 {
22+
23+
// Base64 character set
24+
private static final String BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
25+
private static final char PADDING_CHAR = '=';
26+
27+
private Base64() {
28+
}
29+
30+
/**
31+
* Encodes the given byte array to a Base64 encoded string.
32+
*
33+
* @param input the byte array to encode
34+
* @return the Base64 encoded string
35+
* @throws IllegalArgumentException if input is null
36+
*/
37+
public static String encode(byte[] input) {
38+
if (input == null) {
39+
throw new IllegalArgumentException("Input cannot be null");
40+
}
41+
42+
if (input.length == 0) {
43+
return "";
44+
}
45+
46+
StringBuilder result = new StringBuilder();
47+
int padding = 0;
48+
49+
// Process input in groups of 3 bytes
50+
for (int i = 0; i < input.length; i += 3) {
51+
// Get up to 3 bytes
52+
int byte1 = input[i] & 0xFF;
53+
int byte2 = (i + 1 < input.length) ? (input[i + 1] & 0xFF) : 0;
54+
int byte3 = (i + 2 < input.length) ? (input[i + 2] & 0xFF) : 0;
55+
56+
// Calculate padding needed
57+
if (i + 1 >= input.length) {
58+
padding = 2;
59+
} else if (i + 2 >= input.length) {
60+
padding = 1;
61+
}
62+
63+
// Combine 3 bytes into a 24-bit number
64+
int combined = (byte1 << 16) | (byte2 << 8) | byte3;
65+
66+
// Extract four 6-bit groups
67+
result.append(BASE64_CHARS.charAt((combined >> 18) & 0x3F));
68+
result.append(BASE64_CHARS.charAt((combined >> 12) & 0x3F));
69+
result.append(BASE64_CHARS.charAt((combined >> 6) & 0x3F));
70+
result.append(BASE64_CHARS.charAt(combined & 0x3F));
71+
}
72+
73+
// Replace padding characters
74+
if (padding > 0) {
75+
result.setLength(result.length() - padding);
76+
for (int i = 0; i < padding; i++) {
77+
result.append(PADDING_CHAR);
78+
}
79+
}
80+
81+
return result.toString();
82+
}
83+
84+
/**
85+
* Encodes the given string to a Base64 encoded string using UTF-8 encoding.
86+
*
87+
* @param input the string to encode
88+
* @return the Base64 encoded string
89+
* @throws IllegalArgumentException if input is null
90+
*/
91+
public static String encode(String input) {
92+
if (input == null) {
93+
throw new IllegalArgumentException("Input cannot be null");
94+
}
95+
96+
return encode(input.getBytes(StandardCharsets.UTF_8));
97+
}
98+
99+
/**
100+
* Decodes the given Base64 encoded string to a byte array.
101+
*
102+
* @param input the Base64 encoded string to decode
103+
* @return the decoded byte array
104+
* @throws IllegalArgumentException if input is null or contains invalid Base64 characters
105+
*/
106+
public static byte[] decode(String input) {
107+
if (input == null) {
108+
throw new IllegalArgumentException("Input cannot be null");
109+
}
110+
111+
if (input.isEmpty()) {
112+
return new byte[0];
113+
}
114+
115+
// Strict RFC 4648 compliance: length must be a multiple of 4
116+
if (input.length() % 4 != 0) {
117+
throw new IllegalArgumentException("Invalid Base64 input length; must be multiple of 4");
118+
}
119+
120+
// Validate padding: '=' can only appear at the end (last 1 or 2 chars)
121+
int firstPadding = input.indexOf('=');
122+
if (firstPadding != -1 && firstPadding < input.length() - 2) {
123+
throw new IllegalArgumentException("Padding '=' can only appear at the end (last 1 or 2 characters)");
124+
}
125+
126+
List<Byte> result = new ArrayList<>();
127+
128+
// Process input in groups of 4 characters
129+
for (int i = 0; i < input.length(); i += 4) {
130+
// Get up to 4 characters
131+
int char1 = getBase64Value(input.charAt(i));
132+
int char2 = getBase64Value(input.charAt(i + 1));
133+
int char3 = input.charAt(i + 2) == '=' ? 0 : getBase64Value(input.charAt(i + 2));
134+
int char4 = input.charAt(i + 3) == '=' ? 0 : getBase64Value(input.charAt(i + 3));
135+
136+
// Combine four 6-bit groups into a 24-bit number
137+
int combined = (char1 << 18) | (char2 << 12) | (char3 << 6) | char4;
138+
139+
// Extract three 8-bit bytes
140+
result.add((byte) ((combined >> 16) & 0xFF));
141+
if (input.charAt(i + 2) != '=') {
142+
result.add((byte) ((combined >> 8) & 0xFF));
143+
}
144+
if (input.charAt(i + 3) != '=') {
145+
result.add((byte) (combined & 0xFF));
146+
}
147+
}
148+
149+
// Convert List<Byte> to byte[]
150+
byte[] resultArray = new byte[result.size()];
151+
for (int i = 0; i < result.size(); i++) {
152+
resultArray[i] = result.get(i);
153+
}
154+
155+
return resultArray;
156+
}
157+
158+
/**
159+
* Decodes the given Base64 encoded string to a string using UTF-8 encoding.
160+
*
161+
* @param input the Base64 encoded string to decode
162+
* @return the decoded string
163+
* @throws IllegalArgumentException if input is null or contains invalid Base64 characters
164+
*/
165+
public static String decodeToString(String input) {
166+
if (input == null) {
167+
throw new IllegalArgumentException("Input cannot be null");
168+
}
169+
170+
byte[] decodedBytes = decode(input);
171+
return new String(decodedBytes, StandardCharsets.UTF_8);
172+
}
173+
174+
/**
175+
* Gets the numeric value of a Base64 character.
176+
*
177+
* @param c the Base64 character
178+
* @return the numeric value (0-63)
179+
* @throws IllegalArgumentException if character is not a valid Base64 character
180+
*/
181+
private static int getBase64Value(char c) {
182+
if (c >= 'A' && c <= 'Z') {
183+
return c - 'A';
184+
} else if (c >= 'a' && c <= 'z') {
185+
return c - 'a' + 26;
186+
} else if (c >= '0' && c <= '9') {
187+
return c - '0' + 52;
188+
} else if (c == '+') {
189+
return 62;
190+
} else if (c == '/') {
191+
return 63;
192+
} else {
193+
throw new IllegalArgumentException("Invalid Base64 character: " + c);
194+
}
195+
}
196+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.thealgorithms.conversions;
2+
3+
/**
4+
* A utility class to convert between Cartesian and Polar coordinate systems.
5+
*
6+
* <p>This class provides methods to perform the following conversions:
7+
* <ul>
8+
* <li>Cartesian to Polar coordinates</li>
9+
* <li>Polar to Cartesian coordinates</li>
10+
* </ul>
11+
*
12+
* <p>The class is final and cannot be instantiated.
13+
*/
14+
public final class CoordinateConverter {
15+
16+
private CoordinateConverter() {
17+
// Prevent instantiation
18+
}
19+
20+
/**
21+
* Converts Cartesian coordinates to Polar coordinates.
22+
*
23+
* @param x the x-coordinate in the Cartesian system; must be a finite number
24+
* @param y the y-coordinate in the Cartesian system; must be a finite number
25+
* @return an array where the first element is the radius (r) and the second element is the angle (theta) in degrees
26+
* @throws IllegalArgumentException if x or y is not a finite number
27+
*/
28+
public static double[] cartesianToPolar(double x, double y) {
29+
if (!Double.isFinite(x) || !Double.isFinite(y)) {
30+
throw new IllegalArgumentException("x and y must be finite numbers.");
31+
}
32+
double r = Math.sqrt(x * x + y * y);
33+
double theta = Math.toDegrees(Math.atan2(y, x));
34+
return new double[] {r, theta};
35+
}
36+
37+
/**
38+
* Converts Polar coordinates to Cartesian coordinates.
39+
*
40+
* @param r the radius in the Polar system; must be non-negative
41+
* @param thetaDegrees the angle (theta) in degrees in the Polar system; must be a finite number
42+
* @return an array where the first element is the x-coordinate and the second element is the y-coordinate in the Cartesian system
43+
* @throws IllegalArgumentException if r is negative or thetaDegrees is not a finite number
44+
*/
45+
public static double[] polarToCartesian(double r, double thetaDegrees) {
46+
if (r < 0) {
47+
throw new IllegalArgumentException("Radius (r) must be non-negative.");
48+
}
49+
if (!Double.isFinite(thetaDegrees)) {
50+
throw new IllegalArgumentException("Theta (angle) must be a finite number.");
51+
}
52+
double theta = Math.toRadians(thetaDegrees);
53+
double x = r * Math.cos(theta);
54+
double y = r * Math.sin(theta);
55+
return new double[] {x, y};
56+
}
57+
}

0 commit comments

Comments
 (0)