JetBrains Academy: Map - Kamil-Jankowski/Learning-JAVA GitHub Wiki

JetBrains Academy: Map

Creating a map:

Create TreeMap by name map in any way known to you and fill it with the following three key - value pairs:

Omega - 24
Alpha - 1
Gamma - 3

where strings - keys and numbers - values.

import java.util.*;

public class Main {
    public static void main(String[] args) {

        SortedMap<String, Integer> map = new TreeMap<>();
        map.put("Omega", 24);
        map.put("Alpha", 1);
        map.put("Gamma", 3);

        System.out.println(map);
    }
}

Displaying pairs:

The map is given. Output each its key-value pair in the loop with a new line.

Each line must be in form of key=value (for example, Gamma=3).

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Map<String, Integer> map = new TreeMap<>();
        map.put("Gamma",  3);
        map.put("Omega", 24);
        map.put("Alpha",  1);

        Set<String> keys = map.keySet();
        for (String key : keys){
            System.out.println(String.format("%s=%d", key, map.get(key)));
        }
    }
}

Processing maps - 1:

Modify and return the given map as follows: If the key "a" has a value, set the key "b" to have that same value. In all cases remove the key "c", leaving the rest of the map unchanged.

import java.util.*;

class MapUtils {

    public static void mapShare(Map<String, String> map) {

        if(map.containsKey("a")){
            String valueOfA = map.get("a");
            if(map.containsKey("b")){
                map.replace("b", valueOfA);
            } else {
                map.put("b", valueOfA);
            }
        }
        map.remove("c");
    }

}

/* Do not modify code below */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Map<String, String> map = new HashMap<>();
        while (scanner.hasNextLine()) {
            String s = scanner.nextLine();
            String[] pair = s.split(":");
            map.put(pair[0], pair[1]);
        }
        MapUtils.mapShare(map);
        map.forEach((key, value) -> System.out.println(key + ":" + value));
    }
}

Counting words:

Given an array of strings implement these two methods:

  • On wordCount() return a SortedMap<String, Integer> with a key for each different string, with the value the number of times that string appears in the array. The method takes an array of strings as input.
  • On printMap() using System.out.println() print all items of the Map ("key : value")
import java.util.*;

class MapUtils {

    public static SortedMap<String, Integer> wordCount(String[] strings) {
        SortedMap<String, Integer> counter = new TreeMap<>();
        for (String element : strings){
            if (counter.containsKey(element)){
                int count = counter.get(element) + 1;
                counter.put(element, count);
            } else {
                counter.putIfAbsent(element, 1);
            }
        }
        return counter;
    }

    public static void printMap(Map<String, Integer> map) {
        /*
        for (String key : map.keySet()){
            System.out.println(key + " : " + map.get(key));
        }
        */
        
        /*
        for (Map.Entry<String, Integer> entry : map.entrySet()){
            System.out.println(entry.getKey() + " : " + entry.getValue());
        }
        */

        map.forEach((key, value) -> System.out.println(key + " : " + value));
    }

}

/* Do not change code below */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String[] words = scanner.nextLine().split(" ");
        MapUtils.printMap(MapUtils.wordCount(words));
    }
}

Processing maps - 2:

Modify and return the given map as follows: if the first key % 2 != 0 return sub-map from First Key inclusive to FirstKey+4 inclusive in descending order else return sub-map from LastKey-4 inclusive to the Last Key inclusive in descending order

Sample Input 1:
1:one 2:two 3:three 4:four 5:five 6:six 7:seven

Sample Output 1:

  • 5 : five
  • 4 : four
  • 3 : three
  • 2 : two
  • 1 : one
import java.util.*;

class MapUtils {

    public static NavigableMap<Integer, String> getSubMap(NavigableMap<Integer, String> map){
        if(map.firstKey() % 2 != 0){
            int upperBound = map.firstKey()+5;
            SortedMap<Integer, String> variant1 = map.headMap(upperBound);
            return ((NavigableMap<Integer, String>)variant1).descendingMap();
        } else {
            int lowerBound = map.lastKey()-4;
            SortedMap<Integer, String> variant2 = map.tailMap(lowerBound);
            return ((NavigableMap<Integer, String>)variant2).descendingMap();
        }
    }
}

/* Do not modify code below */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        TreeMap<Integer, String> map = new TreeMap<>();
        Arrays.stream(scanner.nextLine().split("\\s")).forEach(s -> {
            String[] pair = s.split(":");
            map.put(Integer.parseInt(pair[0]),pair[1]);
        });
        NavigableMap<Integer, String> res = MapUtils.getSubMap(map);
        res.forEach((k, v) -> System.out.println(k + " : " + v));
    }
}

War and peace:

When Anthony read "War and Peace", he wondered how many words and how much of them were used in this book.

Help Anthony to write a simplified version of a program that can count the words, separated by a space and output the resulting statistics.

The program must read one line from the standard input and for each unique word in this line output the count of its repeated occurrence (case insensitive) in the "word amount" format (see the output example).

The order of words output may be arbitrary. Each unique word must appear in the output only once.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String[] words = scanner.nextLine().replace(",", "")
                                           .replace(".", "")
                                           .replace("‘", "").split(" ");
        MapUtils.printMap(MapUtils.wordCount(words));
    }
}

class MapUtils {
    static Map<String, Integer> wordCount(String[] strings) {
        Map<String, Integer> counter = new LinkedHashMap<>();
        for (String element : strings){
            element = element.toLowerCase();
            if (counter.containsKey(element)){
                int count = counter.get(element) + 1;
                counter.put(element, count);
            } else {
                counter.putIfAbsent(element, 1);
            }
        }
        return counter;
    }

    static void printMap(Map<String, Integer> map) {
        map.forEach((key, value) -> System.out.println(key + " " + value));
    }
}

Spell checker:

The simplest spell checker is based on a list of known words. Every word in the checked text is searched for in this list and, if such a word was not found, it is marked as erroneous.

Write this spell checker.

The first line of the input contains d – number of records in the list of known word. Next go d lines contain one known word per line, next — the number l of lines of the text, after which — l lines of the text.

Write a program that outputs those words from the text, which are not found in the dictionary (i.e. erroneous). Your spell checker should be case insensitive. The words are entered in an arbitrary order. Words, which are not found in the dictionary, should not be duplicated in the output.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int dictionaryLines = Integer.parseInt(scanner.nextLine());
        SortedMap<String, Integer> dictionary = new TreeMap<>();
        for(int i = 1; i <= dictionaryLines; i++){
            dictionary.put(scanner.nextLine().toLowerCase(), i);
        }

        int inputLines = Integer.parseInt(scanner.nextLine());
        Set<String> text = new HashSet<>();
        for(int i = 0; i < inputLines; i++){
            text.addAll(Arrays.asList(scanner.nextLine().toLowerCase().split(" ")));
        }

        // check if map dictionary contains key equal to provided words
        for (String word : text) {
            if (!dictionary.containsKey(word)){
                System.out.println(word);
            }
        }
    }
}

Substitution cipher:

At some point in the Bioinformatics Institute, biology students no longer understood what did the computer science students said: they spoke a strange set of sounds.

And one of the biologists had suddenly discovered the secret of computer science students: they used the substitution cipher in their communication, i.e. they replaced each symbol of the initial message to the corresponding another symbol. Biologists gained the key to the cipher and now they need help:

Write a program that can encode and decode the substitution cipher. The program accepts two input strings of the same length; the first line contains the characters of the original alphabet, the second line - the symbols of a resulting alphabet, then goes a line you need to encode by the transmitted key, and another line to be decrypted.

For example, the program takes the following input:

abcd
*d%#
abacabadaba
#*%*d*%

You get the following lines, which should be the output of the program:

*d*%*d*#*d*
dacabac

It means that symbol a of the initial message is changed to symbol * in the cipher, b changed to d, c — to % and d — to #. You need to encode the string abacabadaba and decode the string #*%d% using this cipher.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String alphabet = scanner.nextLine();
        String cipherKey = scanner.nextLine();
        String message = scanner.nextLine();
        String cipheredMessage = scanner.nextLine();

        Map encoder = Enigma.createCipher(alphabet, cipherKey);
        Map decoder = Enigma.createCipher(cipherKey, alphabet);
        Enigma.printProcessedMessages(message, cipheredMessage, encoder, decoder);
    }
}

class Enigma {
    static Map createCipher(String alphabet, String cipherKey) {
        List<String> keys = Arrays.asList(alphabet.split(""));
        List<String> values = Arrays.asList(cipherKey.split(""));
        Map<String, String> cipher = new LinkedHashMap<>();
        for (int i = 0; i < keys.size(); i ++){
            cipher.putIfAbsent(keys.get(i), values.get(i));
        }
        return cipher;
    }

    private static String processMessage(String message, Map<String, String> code) {
        List<String> codedMessage = Arrays.asList(message.split(""));
        for(int i = 0; i < codedMessage.size(); i++){
            codedMessage.set(i, code.get(codedMessage.get(i)));
        }

        StringBuilder sb = new StringBuilder();
        for (String s : codedMessage)
        {
            sb.append(s);
        }

        return sb.toString();
    }

    static void printProcessedMessages(String toCipher, String toDecode, Map<String, String> code, Map<String, String> decode) {
        System.out.println(processMessage(toCipher, code));
        System.out.println(processMessage(toDecode, decode));
    }

}

Multiset:

A multiset is a generalization of the concept of a set. Unlike sets, it can store duplicate elements. The number of instances of an element is the multiplicity.

For example, given the following multiset:

{a, a, b, b, b, c}

The multiplicity of a is 2, the multiplicity of b is 3, the multiplicity of c is 1. If a multiset does not have an element, the multiplicity of it is 0.

Write an implementation of the provided generic interface Multiset. The template for your generic class named HashMultiset is given as well. You should implement all methods of the class, according to its interface. You also can add additional methods for helping.

Read the given interface to understand the common multiset operations (add, remove, union, intersection and so one).

Do not forget to test your class. If your implementation is not correct, the testing system gives you a hint throwing an exception with a text, like:

Exception in thread "main" java.lang.AssertionError: size() returned an incorrect result

When you pass your solution to the submit form, do not remove the interface and do not make it and the class public.

interface Multiset<E> {

    /**
     * Add an element to the multiset.
     * It increases the multiplicity of the element by 1.
     */
    void add(E elem);

    /**
     * Remove an element from the multiset.
     * It decreases the multiplicity of the element by 1.
     */
    void remove(E elem);

    /**
     * Union this multiset with another one. The result is the modified multiset (this).
     * It will contain all elements that are present in at least one of the initial multisets.
     * The multiplicity of each element is equal to the maximum multiplicity of
     * the corresponding elements in both multisets.
     */
    void union(Multiset<E> other);

    /**
     * Intersect this multiset with another one. The result is the modified multiset (this).
     * It will contain all elements that are present in the both multisets.
     * The multiplicity of each element is equal to the minimum multiplicity of
     * the corresponding elements in the intersecting multisets.
     */
    void intersect(Multiset<E> other);

    /**
     * Returns multiplicity of the given element.
     * If the set doesn't contain it, the multiplicity is 0
     */
    int getMultiplicity(E elem);
    
    /**
     * Sets multiplicity of the given element.
     */
    void setMultiplicity(E elem, int multiplicity);

    /**
     * Check the multiset contains an element,
     * i.e. the multiplicity > 0
     */
    boolean contains(E elem);

    /**
     * The number of unique elements
     */
    int numberOfUniqueElements();

    /**
     * The size of the multiset, including repeated elements
     */
    int size();

    /**
     * The set of unique elements (without repeating)
     */
    Set<E> toSet();
}

class HashMultiset<E> implements Multiset<E> {

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

    @Override
    public void add(E elem) {
        if (map.containsKey(elem)){
            map.replace(elem, getMultiplicity(elem) + 1);
        } else {
            map.putIfAbsent(elem, 1);
        }
    }

    @Override
    public void remove(E elem) {
        if(map.containsKey(elem) && getMultiplicity(elem) > 0) {
            map.replace(elem, getMultiplicity(elem) - 1);
            if(getMultiplicity(elem) == 0){ map.remove(elem);}
        }
    }

    @Override
    public void union(Multiset<E> other) {
        for (E elem : other.toSet()){
            map.putIfAbsent(elem, other.getMultiplicity(elem));
        }
        for (E elem : this.toSet()){
            setMultiplicity(elem, Math.max(this.getMultiplicity(elem), other.getMultiplicity(elem)));
        }
    }

    @Override
    public void intersect(Multiset<E> other) {
        this.toSet().removeIf(e -> !(other.contains(e)));

        /*
        Set<E> temp = this.toSet();
        for(Iterator<E> iterator = temp.iterator(); iterator.hasNext();){
            if (!(other.contains(iterator.next()))){
                iterator.remove();
            }
        }
         */

        for (E elem : this.toSet()){
            setMultiplicity(elem, Math.min(this.getMultiplicity(elem), other.getMultiplicity(elem)));
        }
    }

    @Override
    public int getMultiplicity(E elem) {
        return map.getOrDefault(elem, 0);
    }

    @Override
    public void setMultiplicity(E elem, int multiplicity){
        map.put(elem, multiplicity);
    }

    @Override
    public boolean contains(E elem) {
        return getMultiplicity(elem) > 0;
    }

    @Override
    public int numberOfUniqueElements() {
        // works if key with value 0 is removed from map
        return toSet().size();
        /*
        // works even if the key with value 0 is not removed from map
        int counter = 0;
        for (E elem : toSet()){
            counter = getMultiplicity(elem) > 0 ? counter+1 : counter;
        }
        return counter;
         */
    }

    @Override
    public int size() {
        int size = 0;
        for (E elem : toSet()){
            size += getMultiplicity(elem);
        }
        return size;
    }

    @Override
    public Set<E> toSet() {
        return map.keySet();
    }
}

Getting submaps:

Write a program that reads key-value pairs and outputs pairs whose keys belongs to the specified range (inclusive) in the ascending order by the key.

Input data format:
The first line contains two values - range borders. The second line contains the number of key-value pairs. Next lines contain pair (an integer key and a string value separated by a space).

Output data format:
All pairs whose keys belong to the range. Each pair in a new line. The key and the value of a pair must be separated by a space.

import java.util.*;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Map<Integer, String> map = new HashMap<>();

        int lowerBound = scanner.nextInt();
        int upperBound = scanner.nextInt();
        int size = scanner.nextInt();
        scanner.nextLine();

        for (int i = 0; i < size; i++){
            int key = Integer.parseInt(scanner.next());
            map.put(key, scanner.next());
        }

        SortedMap subMap = MapUtils.createSubMap(map, lowerBound, upperBound);
        MapUtils.printMap(subMap);
    }
}

class MapUtils {
    static SortedMap createSubMap(Map<Integer, String> map, int lowerBound, int upperBound){
        SortedMap<Integer, String> subMap = new TreeMap<>();

        for (Integer key : map.keySet()){
            if (key >= lowerBound && key <= upperBound){
                subMap.put(key, map.get(key));
            }
        }
        return subMap;
    }

    static void printMap(Map<Integer, String> map) {
        map.forEach((key, value) -> System.out.println(key + " " + value));
    }
}

Sherlock Holmes - 1:

In this problem, you are Sherlock Holmes and you want to find all anagrams.

You have two words. If the words are an anagram, print "yes", else "no".

Note: anagrams are words which contain the same characters with the same frequencies.

For example:

  • "ppaaagg" (p - 2; a - 3; g - 2) and "gagaapp" (p - 2; a - 3; g - 2) are anagrams;
  • "hello" (h - 1; e - 1; l - 2; o - 1) and "helllo" (h - 1; e - 1; l - 3; o - 1) are not anagrams.

Remember: anagrams are case-insensitive

import java.util.*;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String word1 = scanner.nextLine();
        String word2 = scanner.nextLine();

        boolean ifAnagram = MapUtils.anagramCheck(word1, word2);
        System.out.println(ifAnagram ? "yes" : "no");
    }
}

class MapUtils {
    static boolean anagramCheck(String word1, String word2){
        Multiset<Character> first = new HashMultiset<>();
        Multiset<Character> second = new HashMultiset<>();
        for (int i = 0; i < word1.length(); i++){
            first.add(word1.toLowerCase(Locale.US).charAt(i));
        }
        for (int i = 0; i < word2.length(); i++){
            second.add(word2.toLowerCase(Locale.US).charAt(i));
        }

        return first.compare(second);
    }
}

class HashMultiset<E> implements Multiset<E> {

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

    @Override
    public void add(E elem) {
        if (map.containsKey(elem)){
            map.replace(elem, getMultiplicity(elem) + 1);
        } else {
            map.putIfAbsent(elem, 1);
        }
    }

    @Override
    public boolean compare(Multiset<E> other) {
        if (this.size() == other.size()){
            for (E elem : this.toSet()){
                if (this.getMultiplicity(elem) != other.getMultiplicity(elem)){
                    return false;
                }
            }
            return true;
        }
        return false;
    }

        @Override
    public int getMultiplicity(E elem) {
        return map.getOrDefault(elem, 0);
    }

        @Override
    public int size() {
        int size = 0;
        for (E elem : toSet()){
            size += getMultiplicity(elem);
        }
        return size;
    }

    @Override
    public Set<E> toSet() {
        return map.keySet();
    }
}

interface Multiset<E> {

    /**
     * Add an element to the multiset.
     * It increases the multiplicity of the element by 1.
     */
    void add(E elem);

    /**
     * Compares if @param other equals (this) multiset.
     * If there is the same number of same elements - they are equal.
     * @return - boolean value true if equal, otherwise false.
     */
    boolean compare(Multiset<E> other);

    /**
     * Returns multiplicity of the given element.
     * If the set doesn't contain it, the multiplicity is 0
     */
    int getMultiplicity(E elem);

    /**
     * The size of the multiset, including repeated elements
     */
    int size();

    /**
     * The set of unique elements (without repeating)
     */
    Set<E> toSet();
}

Kidnapper of Ice cream:

Now you are a kidnapper of ice cream, you need to write a note to get some money, but you do not want to be busted. So you get a newspaper and find available words.

In this problem, you get two lines: one - available words you have in a newspaper, another second - your note. Print if you can write a note from available words("You get money") or you will be busted("You are busted").

Remember: note case-sensitive

import java.util.*;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String line1 = scanner.nextLine();
        String line2 = scanner.nextLine();

        MapUtils.createSentence(line1, line2);
    }
}

class MapUtils {
    /**
     * Prints "You get money" when you can build a
     * @param sent
     * or "You are busted" if you can't, depending on available words provided in
     * @param dict
     */
    static void createSentence(String dict, String sent){
        Multiset<String> dictionary = new HashMultiset<>();
        Multiset<String> sentence = new HashMultiset<>();
        List<String> dictionaryList = Arrays.asList(dict.split(" "));
        List<String> sentenceList = Arrays.asList(sent.split(" "));

        for (String word : dictionaryList) {
            dictionary.add(word);
        }
        for (String word : sentenceList) {
            sentence.add(word);
        }

        System.out.println(dictionary.containsAll(sentence) ? "You get money" : "You are busted");

    }
}

class HashMultiset<E> implements Multiset<E> {

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

    @Override
    public void add(E elem) {
        if (map.containsKey(elem)){
            map.replace(elem, getMultiplicity(elem) + 1);
        } else {
            map.putIfAbsent(elem, 1);
        }
    }

    @Override
    public int getMultiplicity(E elem) {
        return map.getOrDefault(elem, 0);
    }

    @Override
    public boolean containsAll(Multiset<E> other) {
        for(E elem : other.toSet()){
            if (other.getMultiplicity(elem) > this.getMultiplicity(elem)){
                return false;
            }
        }
        return true;
    }

    @Override
    public Set<E> toSet() {
        return map.keySet();
    }
}

interface Multiset<E> {

    /**
     * Add an element to the multiset.
     * It increases the multiplicity of the element by 1.
     */
    void add(E elem);

    /**
     * Returns multiplicity of the given element.
     * If the set doesn't contain it, the multiplicity is 0
     */
    int getMultiplicity(E elem);

    /**
     * Check if (this) multiset contains all elements from
     * @param other multiset,
     * i.e. the this multiplicity >= other multiplicity
     */
    boolean containsAll(Multiset<E> other);

    /**
     * The set of unique elements (without repeating)
     */
    Set<E> toSet();
}

Sherlock Holmes - 2:

For this problem, imagine that you are Sherlock Holmes. You've deduced that the clues are somehow hidden within the pairs of words that contain only the same letters with the same frequencies. To crack the case, you now need to find out how many characters must be deleted to get such words (character sequences) from the given ones.

For example: for two words "case" and "seal" you'll need to remove characters "c" and "l" respectively to get "ase" and "sea". In this case, the answer is 2 ("c" and "l").

Remember: these "words" are case-insensitive.

import java.util.*;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String word1 = scanner.nextLine();
        String word2 = scanner.nextLine();

        MapUtils.comparatorSherlock(word1, word2);
    }
}

class MapUtils {
    /**
     * Converts provided
     * @param word
     * to a case-insensitive
     * @return multiset of Characters.
     */
    private static Multiset<Character> convertToMultiset(String word){
        Multiset<Character> multiset = new HashMultiset<>();
        for (int i = 0; i < word.length(); i++){
            multiset.add(word.toLowerCase(Locale.US).charAt(i));
        }
        return multiset;
    }

    /**
     * Compares provided
     * @param word1
     * @param word2
     * and
     * @return number of different characters (or they frequencies).
     */
    static void comparatorSherlock(String word1, String word2){
        Multiset<Character> first = convertToMultiset(word1);
        Multiset<Character> second = convertToMultiset(word2);

        System.out.println(first.countDifference(second));
    }
}

class HashMultiset<E> implements Multiset<E> {

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

    @Override
    public void add(E elem) {
        if (map.containsKey(elem)){
            map.replace(elem, getMultiplicity(elem) + 1);
        } else {
            map.putIfAbsent(elem, 1);
        }
    }

    @Override
    public int countDifference(Multiset<E> other) {
        int counter = 0;
        for (E elem : this.toSet()) {
            if (this.getMultiplicity(elem) > other.getMultiplicity(elem)) {
                counter += this.getMultiplicity(elem) - other.getMultiplicity(elem);
            }
        }
        for (E elem : other.toSet()) {
            if (other.getMultiplicity(elem) > this.getMultiplicity(elem)) {
                counter += other.getMultiplicity(elem) - this.getMultiplicity(elem);
            }
        }

        return counter;
    }

    @Override
    public int getMultiplicity(E elem) {
        return map.getOrDefault(elem, 0);
    }

    @Override
    public Set<E> toSet() {
        return map.keySet();
    }
}

interface Multiset<E> {

    /**
     * Add an element to the multiset.
     * It increases the multiplicity of the element by 1.
     */
    void add(E elem);

    /**
     * Counts number of elements to be deleted from both
     * @param other and (this) multiset.
     * @return - number of elements to delete from both (this) and
     * @param other multiset, so they would be equal.
     */
    int countDifference(Multiset<E> other);

    /**
     * Returns multiplicity of the given element.
     * If the set doesn't contain it, the multiplicity is 0
     */
    int getMultiplicity(E elem);

    /**
     * The set of unique elements (without repeating)
     */
    Set<E> toSet();
}

⚠️ **GitHub.com Fallback** ⚠️