gayathri
gayathri

Reputation: 49

Least repeating chararcter in a string

I'm trying to find the least repeating character in a string ,it works for some input but it fails for some input.

Map<Character, Integer> map = new HashMap<Character, Integer> ();

    String s = "abcdabcdabcdacd";
    char[] chars = s.toCharArray();

    for (Character ch: chars) {
        if (map.containsKey(ch)) {
            map.put(ch, map.get(ch) + 1);
        } else {
            map.put(ch, 1);
        }
    }

    Set<Character> keys = map.keySet();

    for (Character ch: keys) {
        if (map.get(ch) ==1) {
            System.out.println(ch + " ");
        }
    }

I expect the output to be b but it doesn't show anything. If i give aabaa as the input then it shows b and that's correct.

Upvotes: 2

Views: 2146

Answers (4)

Nicholas K
Nicholas K

Reputation: 15423

Using streams you may simply do:

final String s = "abcdabcdabcdacd";

String leastRepeated = 
   s.chars().mapToObj(i -> Character.toString((char) i))      // map to Stream<String>   
    .collect(Collectors.toMap(k -> k, v -> 1, Integer::sum))  // Map<String, Integer>
    .entrySet().stream()                                      // stream over map
    .min(Comparator.comparing(Entry::getValue))               // comparing values in map
    .get().getKey();                                          // get resp entry   

which outputs:

b

Upvotes: 1

Matthew
Matthew

Reputation: 1943

The reason your code doesn't work the way you would want it to is because your last code block is only printing if the character is being repeated once and only once:

for (Character ch: keys) {
    if (map.get(ch) ==1) {
        System.out.println(ch + " ");
    }

However by using the Collections.min method we can find the lowest map value which we can then use to find the character it belongs to from map keys. Here is the complete code with context:

/**
 * @return an array of Character objects that have occured the
 * least amount of times in the given {@code String} parameter.
 * <i>Note that all whitespaces found within the {@code String} will be ignored </i>
 */
public static Character[] getLeastRepeatingCharacters(String text) {

    Map<Character, Integer> map = new HashMap<Character, Integer> ();
    /*
     * Remove all whitespaces from the text as we don't
     * want to include them in our comparison oprations
     */
    text = text.replaceAll("\\s+","");

    for (Character ch : text.toCharArray()) {
        if (map.containsKey(ch)) {
            map.put(ch, map.get(ch) + 1);
        }
        else if (ch != '\0') {
            map.put(ch, 1);
        }
    }
    /*
     * Get map value that occurs the least amount of times
     */
    int leastOccuranceValue = Collections.min(map.values());
    java.util.List<Character> leastOccurances = new java.util.ArrayList<>();
    /*
     * Iterate through the map, find all characters that have
     * occured the least amount of times and add them to a list
     */
    for (java.util.Map.Entry<Character, Integer> entry : map.entrySet()) {
        if (entry.getValue().equals(leastOccuranceValue)) {
            leastOccurances.add(entry.getKey());
        }
    }
    return leastOccurances.toArray(new Character[0]);
}

public static void main(String[] args) {

    String text = "abcdabcdabcdacd";
    Character[] leastRepeating = getLeastRepeatingCharacters(text);

    String log = "Array of charactes that repeated the least amount of times in text '%s':%n%s";
    System.out.printf(log, text, Arrays.toString(leastRepeating));
}

Output:

Your string sample:

Array of charactes that repeated the least amount of times in text 'abcdabcdabcdacd ':
[b]

String sample provided by Stultuske:

Array of charactes that repeated the least amount of times in text 'kambcxdabcdalbcdacd ':
[x, k, l, m]

Upvotes: 0

minus
minus

Reputation: 2786

You have to read the whole map to get the min occurrence, so you can't print in the loop, you should instead collect chars with min occurence, and then print them.

    public static void main(String[] args) {
        Map<Character, Integer> map = new HashMap<>();

        String s = "abcdaybcdabcdacdz";
        char[] chars = s.toCharArray();

        for (Character ch: chars) {
            if (map.containsKey(ch)) {
                map.put(ch, map.get(ch) + 1);
            } else {
                map.put(ch, 1);
            }
        }

        List<Character> reps = new ArrayList<>();

        Integer count = chars.length;
        Set<Entry<Character, Integer>> entries = map.entrySet();
        for (Entry<Character, Integer> entry : entries) {
            Integer n = entry.getValue();
            Character c = entry.getKey();
            if(n==count) {
                reps.add(c);
            }else if (n<count) {
                reps = new ArrayList<>();
                reps.add(c);
                count = n;
            }
        }

        for (Character character : reps) {
            System.out.println(character);
        }

    }

Upvotes: 0

Stultuske
Stultuske

Reputation: 9437

As I commented already, you only check for characters which only occur once, not for the least occurrence.

You can change your code by this:

public class PrintB {

    public static void main(String[] args) {
        Map<Character, Integer> map = new HashMap<>();

        String s = "abcdabcdabcdacd";
        char[] chars = s.toCharArray();

        for (Character ch: chars) {
            if (map.containsKey(ch)) {
                map.put(ch, map.get(ch) + 1);
            } else {
                map.put(ch, 1);
            }
        }

        Set<Character> keys = map.keySet();
        boolean broken = false;
        for ( int i = 0; i < s.length(); i++ ) { // the max will be s.length()

            for (Character ch : keys) {
                if (map.get(ch) == i) { // this amount is checked for each char
                    System.out.println(ch + " ");
                    broken = true;
                }
            }
            if ( broken ) {
                i = s.length(); // sure, there are other ways to break out of the loop
            }
        }
    }
}

Upvotes: 2

Related Questions