-2

Could please optimize the code below..

Requirement : Print the First repeat character in a string and their positions. Example : Case 1: String value is "XYABXB" Out put should be : First Repeat Character is : X at position : 1 and repeat character is at position : 5 Case 2: String Value is "AABCDEB" Out put should be : First Repeat Character is : A at position : 1 and repeat character is at position : 2 Case 3: String Value is "ABCDFG" Out Put should be : 'No Repeat character found'

public void printFirstOccuranceOfRepeatCharactor(String inputString){
    char [] words = inputString.toCharArray();
    boolean repeatCharFound = false;
    for (int i = 0; i < words.length; i++) {
        if(!repeatCharFound){
            char charPos = words[i];
            for (int j = i+1; j < words.length; j++) {
                if(charPos == words[j]){
                    System.out.println("First Repeating Char is : "+words[j] + " and First Occurrance is at :" + (i+1) +" And repeat char At position :" + (j+1));
                    repeatCharFound = true;
                    break;
                }
            }
        }
    }
    if(!repeatCharFound){
        System.out.println("No repeat charector found");
    }
}
coder1608
  • 171
  • 6
  • 14
  • First Repeat Character is : A at position : 1 and repeat character is at position : 4 – coder1608 Feb 07 '15 at 15:38
  • not complaining.. I'm just saying that you could achieve this through looping and you don't need to have a regex here. And i'm not the downvoter.. – Avinash Raj Feb 07 '15 at 15:38

4 Answers4

2

Just use Map<Character, Integer> with char and position in array and then keep on adding. Call Map's get method and if it returns position then that's what you would return.

Map<Character, Integer> map = new HashMap<Character, Integer>();
Integer number;
for (int i =0; i<words.length; i++) {
    number = map.get(words[i]);
    if (number != null) {
        return number;//that's the position
    } else {
        map.put(words[i], i)
    }
}
System.out.println("No repeat charector found");
SMA
  • 36,381
  • 8
  • 49
  • 73
1

Here is a solution using only primitive java features, that uses a boolean array to mark characters already "hit". It relies on the order of the ASCII Table, as well as the string having only uppercase characters:

private static void printRepeats(String test) {
    // "only upper-case characters" requires options 'A' to 'Z'.
    // this is asciiValue('Z') - asciiValue('A') (implicitly done by Java) + 1
    boolean[] charHits = new boolean['Z' - 'A' + 1];

    for (int i=0; i < test.length(); i++){
        // our current character
        char current = test.charAt(i);
        if (charHits[current - 'A']){
            // character index already set in charHits array - already seen!
            // print and return
            System.out.println(
                current + " is repeated, first occurrence "
                + test.indexOf(current) + ", second: " + i
            );
            return;
        } else {
            // first hit - mark as already occurred for future iterations
            charHits[current - 'A'] = true;
        }
    }
    // no character repeats found
    System.out.println("No repeats");
}

The idea is to iterate the string, and every time we see a character, check if we already saw it. If we did, we immediately print and return. If we didn't - we mark it as already "hit" and proceed.

Code walkthrough (printRepeats):

Part 1 - Array allocation:

To store our "hits" we need a data structure we can lookup past characters. The first statement creates an array just the size we need. Since uppercase letters are continuous in the ASCII table (A - 65 through Z - 90), we know we need only a [90 - 65 + 1 = 26] size array to accomodate all uppercase letters. Each character hit is mapped to an index in the array that is [the characters ASCII value] - [A's ASCII value]. So:

LETTER -> INDEX IN ARRAY
'A' -> 0
'B' -> 1
...
'Z' -> 25

So to allocate such array we use:

boolean[] charHits = new boolean['Z' - 'A' + 1];

This is exactly like:

new boolean[26];

You can check with:

System.out.println('Z' - 'A' + 1); // 26

Or even:

System.out.println(new boolean['Z' - 'A' + 1].length); // 26

Part 2 - String iteration:

This part iterates the given String and has two options:

  1. Mark a characters as seen
  2. Spot duplicate, print and return

    • It's useful to know that boolean arrays are automatically initialized to false, so we can rely on that.

Loop code:

    for (int i=0; i < test.length(); i++){
        // our current character
        char current = test.charAt(i);
        if (charHits[current - 'A']){
            // character index already set in charHits array - already seen!
            // print and return
            System.out.println(
                current + " is repeated, first occurrence "
                + test.indexOf(current) + ",  second repeat: " + i
            );
            return;
        } else {
            // first hit - mark as already occurred for future iterations
            charHits[current - 'A'] = true;
        }
    }
    // no character repeats found - no index in array hit twice
    System.out.println("No repeats");
}

The print part could be further optimized by storing the first occurence's index alongside it's "seen/not seen" status using some clever mapping to a primitive object instead of using String.indexOf, but it would lessen code readability.

Tip: I don't bother with memorizing specific ASCII Table values (nor should anyone). I only memorize the ASCII Table's order (this case - the uppercase english alphabet being continuous).

Bonus - a short, wasteful, version:

A shorter version can be composed as follows:

For each possible prefix (short to long), check if the first character after the prefix is in the prefix. If it is, that's the first repeat.

The code:

public static void printRepeatsShort(String test){
    for (int i=0; i< test.length(); i++){
        // check index of following character in prefix
        int indexInPrefix = test.substring(0, i).indexOf(test.charAt(i));
        if ((indexInPrefix != -1){
            // next character is in prefix, return
            System.out.println(
                "Repeated char: '" + test.charAt(i) + "', First: "
                + indexInPrefix + " Second: " + i
            );
            return;
        }
    }
    System.out.println("No repeats found");
}

This version is far less optimal, but only relies on methods from String, so it's more contained.

Reut Sharabani
  • 30,449
  • 6
  • 70
  • 88
0

Simple and easy solution

import java.util.Scanner;

public class firstrepchar {

    static Scanner sn = new Scanner(System.in);
    static String word = sn.nextLine();

    public static void main(String[] args) {
        System.out.println("The Result is " + check(word));
    }

    private static String check(String word) {
        String store = "";
        for (int i = 0; i < word.length(); i++) {
            if (store.indexOf(word.charAt(i)) < 0) {
                store = store + word.charAt(i);
            } else {
                return word.charAt(i) + " at position " + i;
            }
        }
        System.out.println("Result word " + store);
        return "nothing found";
    }
}
Sai
  • 15,188
  • 20
  • 81
  • 121
0

Short and Simple >

void findFirstDupChar() {
        String s = "google";
        Integer dupIndex = s.length() - 1;
        boolean isDuplicateExists = false;
        Map<Character, Integer> map = new LinkedHashMap<>();

        char[] words = s.toCharArray();
        for (int i = 0; i < words.length; i++) {
            Integer index = map.put(words[i], i);
            if (index != null) {
                if (index < dupIndex) {
                    dupIndex = index;
                    isDuplicateExists = true;
                }
            }
        }
        System.out.println(isDuplicateExists ? words[dupIndex] + ", index=" + dupIndex : "No duplicateds found");
    }

This will print output as following >
g, index=0