Showing posts with label Core Java. Show all posts
Showing posts with label Core Java. Show all posts

Saturday, 3 January 2026

Convert Roman Numeral to Integer (Java)

Convert Roman Numeral to Integer (Java)

In this post, we will learn how to convert a Roman numeral string into its integer value using Java. This solution efficiently handles both normal and subtractive cases using a single traversal.


Problem Statement

Given a Roman numeral string, convert it into its corresponding integer value.

Examples:

VIII   → 8
IX     → 9
LVIII  → 58
MCMXCIV → 1994

Approach Used

  • Traverse the string from right to left
  • Convert each Roman symbol to its integer value
  • Add or subtract values based on Roman numeral rules

Java Code Implementation


public class RomanToInteger {

    public static void main(String[] args) {

        String[] testCases = {
            "VIII",
            "IX",
            "LVIII",
            "MCMXCIV",
            "XL"
        };

        for (String roman : testCases) {
            System.out.println("Roman: " + roman +
                    " → Integer: " + romanToInteger(roman));
        }
    }

    private static int romanToInteger(String st) {

        int result = 0;
        int value = 0;

        for (int i = st.length() - 1; i >= 0; i--) {

            switch (st.charAt(i)) {
                case 'I': value = 1; break;
                case 'V': value = 5; break;
                case 'X': value = 10; break;
                case 'L': value = 50; break;
                case 'C': value = 100; break;
                case 'D': value = 500; break;
                case 'M': value = 1000; break;
            }

            if (value * 4 < result)
                result -= value;
            else
                result += value;
        }

        return result;
    }
}


Explanation

Right-to-Left Traversal

  • Roman numerals follow a subtractive rule (e.g., IV = 4)
  • By scanning from right to left, we can decide whether to add or subtract
  • If the current value is much smaller than the accumulated result, subtract it

Technique Used: Reverse Traversal + Greedy Decision


Sample Output

Roman: VIII → Integer: 8
Roman: IX → Integer: 9
Roman: LVIII → Integer: 58
Roman: MCMXCIV → Integer: 1994
Roman: XL → Integer: 40

Time & Space Complexity

Metric Complexity
Time O(n)
Space O(1)

Interview Tip

The right-to-left traversal avoids extra data structures and is often preferred in interviews for its simplicity and efficiency.


Want to Go Further?

  • Validate invalid Roman numerals
  • Convert Integer to Roman
  • Solve this using a HashMap approach

👉 Tip: This problem is commonly asked in coding interviews and tests understanding of greedy logic.


Category: Strings
Difficulty: Easy
Techniques: Greedy, Reverse Traversal

Check if a String is Palindrome (Java)

Check if a String is Palindrome (Java)

In this post, we will learn how to check whether a given string is a palindrome using Java. We will solve the problem using two different techniques and handle multiple input strings.


What is a Palindrome?

A string is called a palindrome if it reads the same forward and backward.

Examples:

ABCBA  → Palindrome
MADAM  → Palindrome
HELLO  → Not a Palindrome

Approaches Used

  • Naive Approach: Reverse the string and compare
  • Efficient Approach: Two Pointer Technique

Java Code Implementation


public class StringPalindrome {

    public static void main(String[] args) {

        String[] inputs = {"ABCBA", "MADAM", "HELLO", "LEVEL"};

        for (String str : inputs) {
            System.out.println("String: " + str);
            System.out.println("Naive Check: " + isPalindromeNaive(str));
            System.out.println("Efficient Check: " + isPalindromeEfficient(str));
            System.out.println();
        }
    }

    // Naive approach using reverse
    private static boolean isPalindromeNaive(String str) {
        StringBuilder reverse = new StringBuilder(str);
        reverse.reverse();
        return str.equals(reverse.toString());
    }

    // Efficient approach using two pointers
    private static boolean isPalindromeEfficient(String str) {

        int left = 0;
        int right = str.length() - 1;

        while (left < right) {
            if (str.charAt(left) != str.charAt(right)) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}


Explanation

1. Naive Approach (Reverse String)

  • Reverse the given string
  • Compare it with the original string
  • If both are equal, the string is a palindrome

Technique Used: String Reversal


2. Efficient Approach (Two Pointer Technique)

  • Initialize two pointers: one at the start and one at the end
  • Compare characters at both pointers
  • Move pointers inward until they cross
  • If all characters match, it is a palindrome

Technique Used: Two Pointer Technique


Sample Output

String: ABCBA
Naive Check: true
Efficient Check: true

String: MADAM
Naive Check: true
Efficient Check: true

String: HELLO
Naive Check: false
Efficient Check: false

Time & Space Complexity

Approach Time Complexity Space Complexity
Naive O(n) O(n)
Efficient O(n) O(1)

Interview Tip

In interviews, the Two Pointer Technique is preferred because it uses constant extra space and is more efficient.


Category: Strings
Difficulty: Easy
Technique: Two Pointers

Monday, 1 April 2024

Java Evolution: Exploring the Shift from Java 5 to Java 8

 Here's a high-level overview of the differences between Java 5 and Java 8:

  1. Lambda Expressions:

    • Java 8 introduced lambda expressions, allowing developers to write more concise code by enabling functional-style programming. This feature is particularly useful for working with collections and streams.

  2. Stream API:

    • Java 8 introduced the Stream API, which provides a powerful and flexible way to process collections of objects. Streams enable functional-style operations such as map, filter, reduce, and collect, making it easier to work with large datasets.

  3. Functional Interfaces:

    • Java 8 formalized the concept of functional interfaces, interfaces with a single abstract method, by introducing the @FunctionalInterface annotation. This annotation ensures that an interface can be used as a functional interface, making it easier to work with lambda expressions.

  4. Optional Class:

    • Java 8 introduced the Optional class, which provides a way to express optional values instead of relying on null references. This can help to prevent NullPointerExceptions and make code more robust.

  5. Date and Time API:

    • Java 8 introduced a new Date and Time API in the java.time package, which provides a more comprehensive and flexible alternative to the old java.util.Date and java.util.Calendar classes. The new API makes it easier to work with dates, times, and time zones.

  6. Default and Static Methods in Interfaces:

    • Java 8 allowed interfaces to have default and static methods, providing a way to add new methods to interfaces without breaking existing implementations. Default methods have an implementation in the interface itself, while static methods are similar to static methods in classes.

  7. Parallel Array Sorting:

    • Java 8 introduced parallel array sorting using the Arrays.parallelSort() method, which can leverage multiple CPU cores to speed up the sorting process for large arrays.

These are some of the key differences between Java 5 and Java 8 at a high level. Each of these features introduced in Java 8 has significantly improved the language's expressiveness, flexibility, and performance.


Here's a table summarizing the differences between Java 5 and Java 8:

FeatureJava 5Java 8
Lambda ExpressionsNot supportedIntroduced, enabling functional-style programming
Stream APINot availableIntroduced for processing collections in a functional manner
Functional InterfacesNot formalizedFormalized with @FunctionalInterface annotation
Optional ClassNot availableIntroduced to handle optional values and prevent NullPointerExceptions
Date and Time APIRelied on java.util.Date and java.util.CalendarIntroduced a comprehensive java.time package
Default and Static Methods in InterfacesInterfaces could only have abstract methodsIntroduced default and static methods in interfaces
Parallel Array SortingSorting was single-threadedIntroduced parallel array sorting with Arrays.parallelSort()

This table provides a quick comparison of some key features introduced or improved upon in Java 8 compared to Java 5.





Sunday, 15 May 2016

Encryption and Decryption in Java

Encryption and Decryption in Java
In this article I will be giving you basic idea of encryption and decryption in java and how it works.

Encryption is the process of transforming information using an algorithm to make it unreadable to anyone except those possessing special knowledge, usually referred to as a key,.The result of the process is encrypted information,process is called encryption. Reverse of it terms as Decryption.

The core class used for encryption and decryption is javax.crypto.Cipher.

A cipher is an object capable of carrying out encryption and decryption according to an encryption scheme (algorithm).
This class contains a representation of a cipher that uses a specific algorithm and operating mode.It includes methods to initialize and operate cipher.


Types of Encryption

Encryption can be symmetric or asymmetric,based on the user requirement.


Symmetric encryption: - Encryption and decryption can be done symmetrically,here the same key is used to encrypt and decrypt the data. Because both parties have the same key, the decryption essentially is performed by reversing some part of the encryption process. The DES(Data Encryption Standard) algorithm is an example of a symmetric key. It is supported by the Java Cryptography Extension (JCE).

Symmetric encryption is the oldest and best-known technique. A secret key, which can be a number, a word, or just a string of random letters, is applied to the text of a message to change the content in a particular way. This might be as simple as shifting each letter by a number of places in the alphabet. As long as both sender and recipient know the secret key, they can encrypt and decrypt all messages that use this key.

The encryption key is trivially related to the decryption key, in that they may be identical or there is a simple transform to go between the two keys. The keys, in practice, represent a shared secret between two or more parties that can be used to maintain a private information link.

Symmetric-key algorithms can be divided into stream cipher and block cipher. Stream ciphers encrypt the bytes of the message one at a time, and block ciphers take a number of bytes and encrypt them as a single unit. Blocks of 64 bits have been commonly used; the Advanced Encrypted Standard (AES) algorithm approved by NIST in December 2001 uses 128-bit blocks.

In the first case we are requesting a Cipher that implements the Data Encryption Standard (DES) algorithm and in the second line we want a Cipher that uses the Advanced Encryption Standard (AES) algorithm using the Electronic Code Book (ECB) method and the PKCS5 padding scheme. It is important to get to know the algorithms and operations modes available in the target device or emulator.

Algorithms: DES, 3DES/DESede, AES

Modes: ECB, CBC

Padding Schemes: No padding, PKCS5 padding.





Asymmetric encryption:-Here we use of asymmetric key algorithms instead of or in addition to symmetric key algorithms. Using the techniques of public key-private key cryptography. They do not require a secure initial exchange of one or more secret keys as is required when using in symmetric key algorithms.

The problem with secret keys is exchanging them over the Internet or a large network while preventing them from falling into the wrong hands. Anyone who knows the secret key can decrypt the message. One answer is asymmetric encryption, in which there are two related keys--a key pair. A public key is made freely available to anyone who might want to send you a message. A second, private key is kept secret, so that only you know it.

The distinguishing technique used in public key-private key cryptography is use of asymmetric key algorithms because the key used to encrypte a message is not the same as the key used to decrypte it. Each user has a pair of cryptographic keys— a public key and a private key. The private key is kept secret, while the public key may be widely distributed. Messages are encrypted with the recipient's public key and can only be decrypted with the corresponding private key. The keys are related mathematically, but the private key cannot be feasibly (i.e., in actual or projected practice) derived from the public key. It was the discovery of such algorithms which revolutinized the practice of cryptography beginning in the middle 1970s.

In contrast Symmetric encryption,variations of which have been used for some thousands of years, use a single secret key shared by sender and receiver (which must also be kept private, thus accounting for the ambiguity of the common terminology) for both encryption and decryption. To use a symmetric encryption scheme, the sender and receiver must securely share a key in advance.

An analogy to public-key encryption is that of a locked mailbox with a mail slot. The mail slot is exposed and accessible to the public; its location (the street address) is in essence the public key. Anyone knowing the street address can go to the door and drop a written message through the slot; however, only the person who possesses the key can open the mailbox and read the message.


Symmetric vs. asymmetric algorithms:

(1)  Unlike symmetric algorithms, asymmetric key algorithm uses a different key for encryption than for decryption. I.e., a user knowing the encryption key of an asymmetric algorithm can encrypt messages, but cannot derive the decryption key and cannot decrypt messages encrypted with that key.

(2)  Symmetric-key algorithms are generally much less computationally intensive than asymmetric key algorithms. In practice, asymmetric key algorithms are typically hundreds to thousands times slower than symmetric key algorithms.



A conventional encryption scheme has five major parts:

Plaintext - this is the text message to which an algorithm is applied.

Encryption Algorithm - it performs mathematical operations to conduct substitutions and transformations to the plaintext.

Secret Key - This is the input for the algorithm as the key dictates the encrypted outcome.

Ciphertext - This is the encrypted or scrambled message produced by applying the algorithm to the plaintext message using the secret key.

Decryption Algorithm - This is the encryption algorithm in reverse. It uses the ciphertext, and the secret key to derive the plaintext message.



Starting with encryption
 Step 1:- Create a Cipher instance from Cipher class, we have to specify the following information and separated by a slashes (/).

1.  Algorithm name

2.  Mode (optional)

3.  Padding scheme (optional)
  

You need to create a Cipher. You use a factory method of the Cipher class so that you can take advantage of different providers without changing the application. You create a Cipher like this:

Cipher cipher = Cipher.getInstance("DES");

If no mode or padding has been specified, provider-specific default values for the mode and padding scheme are used. For example, the SunJCE provider uses ECB as the default mode, and PKCS5Padding as the default padding scheme for DES, DES-EDE and Blowfish ciphers. This means that in the case of the SunJCE provider,

Cipher c1 = Cipher.getInstance("DES/ECB/PKCS5Padding");



DES = Data Encryption Standard

ECB = Electronic Codebook mode
PKCS5Padding = PKCS #5-style padding


 Step 2:- Create a DES Key.

You create a symmetric key, use a factory method from the KeyGenerator class and pass in the algorithm as a String. When you call the generateKey() method, you get back an object that implements the Key interface instead of the KeyPair interface. The call looks something like this:


SecretKey key =

KeyGenerator.getInstance ("DES").generateKey();


Step 3:- Convert String into Byte[] array format.

String input= “This is the private message";

byte [] textBytes =input.getBytes();

Private message input as string is encrypted with the key specified using the DES symmetric algorithm.


 Step 4:- Make Cipher in encrypt mode, and encrypt it with Cipher.doFinal() method.


Cipher is used to encrypt and decrypt data that is passed in as byte arrays. The two essential methods you must use are init (), to specify which operation will be called, and
  

doFinal (), to perform that operation. For example, the following two lines use the cipher and key instances you created to encrypt a byte array called textBytes. The result is stored in a byte array called encryptedBytes.

Suppose the string to encrypte is in input string object.

cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes =

cipher.doFinal( textBytes );

   

Decryption
First of all you need the same key as you used in the encryption,because DES is the


Symmetric encryption technique.

After encrypting the private message now we need to decrypte it, so

Make Cipher in decrypt mode, and decrypt it with Cipher.doFinal() method as well.

desCipher.init(Cipher.DECRYPT_MODE, key);

byte[] textDecrypted = desCipher.doFinal(textEncrypted);

System.out.println("Text Decryted : " + new String(textDecrypted));

The output string is the same as given in the input for encryption.

As “This is the private message” in the output appears.

Exception handling:-Also for catching the exceptions occurring during the encryption and decryption process.

You need to catch the following exceptions.

Ex:-NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,

IllegalBlockSizeException, BadPaddingException.


If you enjoyed this post, I’d be very grateful if you’d help it spread by emailing it to a friend, or sharing it on Twitter or Facebook. Thank you!