Home > Blockchain >  Speed up the comparison time of two strings
Speed up the comparison time of two strings

Time:06-21

The task is to write the logic of checking the magnitude of the coincidence of the player's attempt with the hidden word. More formally, let there be a string S — a hidden word and a string Q — a player's attempt. Both strings have the same length N. For each position 1 ≤ i ≤ N of string Q, we need to calculate the type of match in this position with string S.

If Q[i] = S[i], then at position i the match type should be equal to "correct".

If Q[i]≠S[i], but there is another position 1 ≤ j≤ N such that Q[i] = S[j], then in position i the match type must be equal to "present".

  • Each letter of the string S can be used in no more than one match of the type "correct" or "present".
  • Priority is always given to the "correct" type.
  • Of all possible use cases in the "present" type, the program selects the leftmost position in the Q string.

In other positions, the match type must be equal to "absent".

Input format:

The first line contains the string S (1≤ S ≤ 10^6) — the hidden word. The second line contains the string Q ( Q = S) — the player's attempt. It is guaranteed that the strings S and Q contain only uppercase Latin letters.

Example:

input: COVER CLEAR

output: correct absent present absent correct

My program does this very slowly, how can I speed it up?


import java.util.*;

public class Task1 {
    private final static String cor = "correct";
    private final static String abs = "absent";
    private final static String pre = "present";
    static String[] stringArr;
    static java.util.Map<Integer, Integer> map = new HashMap<>();

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        String a = sc.nextLine();
        String b = sc.nextLine();

        stringArr = new String[a.length()];
        int length1 = a.length();

        char[] arr1 = a.toCharArray();
        char[] arr2 = b.toCharArray();

        for (int i = 0; i < length1; i  ) {
            if (arr2[i] == arr1[i]) {
                stringArr[i] = cor;
                map.put(i, i);
            }
        }

        for (int i = 0; i < length1; i  ) {
            if (arr2[i] != arr1[i]) {
                while (stringArr[i] == null) {
                    boolean finded = false;
                    for (int j = 0; j < arr1.length; j  ) {
                        if (arr2[i] == arr1[j] && !map.containsKey(j)) {
                            stringArr[i] = pre;
                            finded = true;
                            map.put(j, j);
                            break;
                        }
                    }
                    if (!finded) stringArr[i] = abs;
                }
            }
        }

        for (String s : stringArr) {
            System.out.println(s);
        }
    }
}

CodePudding user response:

You can use an int array (or a HashMap<Char, Integer>) count to store those "presented" characters.

We need two for loops. The first loop will set all "correct" positions (if arr1[i] == arr2[i], then stringArr[i] = cor); and for those unmatched positions (arr1[i] != arr2[i]), we count the number of occurrences for those characters in the hidden word (count[arr1[i] - 'A'] ).

Then in the second for loop, we check those unmatched positions with the help of count.

  • If count[arr2[i] - 'A'] > 0, it means that the hidden word contains the character arr2[i], so we can set stringArr[i] = pre and decrement count[arr2[i] - 'A'] (since each letter can be used once)
  • Otherwise, there's no matching letter in the hidden word, stringArr[i] should be set to abs.
import java.util.Scanner;

public class Task1 {
    private final static String cor = "correct";
    private final static String abs = "absent";
    private final static String pre = "present";

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        String a = sc.nextLine();
        String b = sc.nextLine();

        String[] stringArr = new String[a.length()];
        int length1 = a.length();

        char[] arr1 = a.toCharArray();
        char[] arr2 = b.toCharArray();

        int[] count = new int[26];

        for (int i = 0; i < length1; i  ) {
            if (arr2[i] == arr1[i]) {
                stringArr[i] = cor;
            }
            else {
                count[arr1[i] - 'A']  ;
            }
        }

        for (int i = 0; i < length1; i  ) {
            if (arr1[i] != arr2[i]) {
                if (count[arr2[i] - 'A'] > 0) {
                    stringArr[i] = pre;
                    count[arr2[i] - 'A']--;
                }
                else {
                    stringArr[i] = abs;
                }
            }
        }

        for (String s : stringArr) {
            System.out.println(s);
        }
    }
}

CodePudding user response:

This can be done using hashmaps and taking advantage of the o(1) insert/delete time.

I'm assuming that each word is exactly the same length. Consequently, to get the answer, we need to check each letter in each word. If they have a length of n, then that means at a minimum it will take o(2n) == o(n) to find the answer.

[1] Then, if you're able to use extra space, I would just use a hashmap as an index, where the key is a character in secret, and the value is the set of indices that letter occurs in secret. So it would look something like this:

//cover
c:<0>
o:<1>
etx...

[2] Then check each letter in guess against the index.

  • If there is no key for a letter, the put absent
  • If there is a key, then look in the set of indices to see if there is a matching index. Since I used a hashset, that's another o(1) lookup

So sum total, you walk through secret and guess once each which is o(n) runtime. That, plus o(1) for each index lookup produces o(n) runtime.

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

public class Task1 {

    public static void main(String[] args)
    {
        ArrayList<String> res = solve("COVER", "CLEAR");
        System.out.println(res);
    }

    public static ArrayList<String> solve(String secret, String guess){
        ArrayList<String> result = new ArrayList<>();
        HashMap<Character, HashSet<Integer>> index = new HashMap<>();
        //shortcut
        if(secret.equals(guess)){
            for(int i = 0; i < secret.length(); i  ) result.add("correct");
            return result;
        }
        //make the index of char:<indices> for the chars in "secret"
        for(int i = 0; i < secret.length(); i  ){
            char c = secret.charAt(i);
            HashSet<Integer> bucket = index.get(c);
            if(bucket == null){
                bucket = new HashSet<>();
                index.put(c, bucket);
            }
            bucket.add(i);
        }
        //check each char in "guess" against the index and tally the result
        for(int i = 0; i < guess.length(); i  ){
            char c = guess.charAt(i);
            HashSet<Integer> bucket = index.get(c);
            if(bucket == null) result.add("absent");
            else if(bucket.contains(i)) result.add("correct");
            else result.add("present");
        }
        return result;
    }
}
  • Related