Сократите предложение, используя сокращения на карте - PullRequest
0 голосов
/ 05 февраля 2020

Подсказка: Учитывая предложение и набор известных сокращений, найдите эффективный способ сократить предложение.

 Abbreviations:
 be right back -> BRB
 be right there -> BRT
 be back later -> BBL
 be back soon -> B back soon
 faster than light -> FTL
 be -> B
 later => L8R


 Conversions:
 I will be right there -> I will BRT
 I will be there -> I will B there
 I will go right there -> I will go right there
 I will be there later -> I will B there L8R
 I am faster than you -> I am faster than you
 Never faster than light -> Never FTL
 Faster than light today -> FTL today

Вот мой код этой проблемы. Тем не менее, я могу получить только одно сокращение в своем окончательном ответе.

import java.util.*;
class Solution{
    public static void main(String[] args) {
        Map<String, String> dict = new HashMap<>();
        dict.put("be right back", "BRB");
        dict.put("be right there", "BRT");
        dict.put("be right later", "BRL");
        dict.put("be", "B");
        dict.put("later", "L8R");

        String s = "I will be right there later";
        System.out.println(convert(s, dict));
    }

    public static String convert(String s, Map<String, String> dict) {
        String[] words = s.split(" ");
        List<String> converted = new ArrayList<>();

        List<String> toCheck = new ArrayList<>();
        for (int i = 0; i < words.length; i++){
            for (int j = i; j < words.length; j++){
                String[] substring = Arrays.copyOfRange(words, i, j+1);
                String combined = "";
                for (String str : substring){
                    combined += str + " ";
                }
                combined = combined.strip();
                toCheck.add(combined);
            }
        }

        String ans = "";
        String target = "";
        for (String str : toCheck){
            if (dict.containsKey(str)){
                int index = s.indexOf(str);
                ans = s.substring(0, index) + dict.get(str) + s.substring(index + str.length());
            }
        }

        return ans;

    }

}

Я думаю, что есть рекурсивный способ выполнить преобразование, но я не совсем уверен, как. Может кто-нибудь помочь мне с этим или направить меня к проблеме, подобной этой? Заранее спасибо!

Ответы [ 2 ]

1 голос
/ 05 февраля 2020
ans = s.substring(0, index) + dict.get(str) + s.substring(index + str.length());

Эта строка фактически сохраняет строку без изменений, за исключением запасной части. Таким образом, в ans.

сохраняется только последняя совпадающая строка на карте. Ваш код также не обрабатывает перекрывающиеся регистры, например, faster now, I will be faster now. В таких случаях вы, вероятно, захотите сопоставить I will be faster now для правильного сокращения.

Вот как я это решил. Вы можете использовать регулярные выражения, но на достаточно длинных строках это выглядит медленнее, поскольку регулярное выражение сначала компилируется перед сопоставлением.

Фрагмент:

import java.util.*;
class Solution{
    public static void main(String[] args) {
        Map<String, String> dict = new HashMap<>();
        dict.put("be right back", "BRB");
        dict.put("be right there", "BRT");
        dict.put("be right later", "BRL");
        dict.put("be", "B");
        dict.put("be back soon","B back soon");
        dict.put("faster than light","FTL");
        dict.put("later", "L8R");

        String[] tests = {
            "I will be right there later",
            "I will be right there",
            "I will be there",
            "I will go right there",
            "I will be there later",
            "I am faster than you",
            "Never faster than light",
            "Faster than light today"
        };

        for(String test_case : tests){
            System.out.println(test_case + " => " + convert(test_case, dict));   
        }
    }

    public static String convert(String s, Map<String, String> dict) {

        List<String> dict_words = new ArrayList<>(dict.keySet());
        Map<Integer,String[]> replacement_index = new HashMap<>();

        Collections.sort(dict_words,new Comparator<String>(){
            public int compare(String s1,String s2){
                if(s1.length() == s2.length()) return 0; // order doesn't seem to matter for same length strings
                return s2.length() - s1.length(); // return bigger length string first
            }
        });

        String temp = s.toLowerCase(); // to perform case insensitive match
        for(String dict_str : dict_words){
            String dict_str_lower = dict_str.toLowerCase(); // to perform case insensitive match
            int index = 0;
            do{
                index = temp.indexOf(dict_str_lower,index);
                if(index != -1){
                    replacement_index.putIfAbsent(index,new String[]{dict.get(dict_str),dict_str});
                    index++;// to get the next match index of the same word in the string.
                }
            }while(index != -1 && index < temp.length());
        }

        StringBuilder res = new StringBuilder("");

        for(int i = 0;i < s.length(); ++i){
            if(replacement_index.containsKey(i)){
                res.append(replacement_index.get(i)[0]);
                i += replacement_index.get(i)[1].length() - 1;
            }else{
                res.append(s.charAt(i));
            }
        }

        return res.toString();
    }

}

Демо: https://ideone.com/pIj5dI

Алгоритм:

  • В приведенном выше коде мы сначала получаем все сопоставить значения в списке и отсортировать их в порядке убывания длины.

  • Мы делаем это, чтобы избежать проблем с наложением, как описано выше, чтобы сначала сопоставить более крупные строки, а затем иметь дело с более мелкими строками.

  • Второе - получить все совпадающие индексы значений на карте и сохранить их на другой карте для получения окончательных результатов.

  • Третье - это l oop поверх строки, как есть, и если у нас есть текущий индекс в итерации на нашей карте (точнее, в replacement_index), то мы добавляем значение замены из нашей карты и перемещаем указатель в местоположение, большее, чем длина замены .

Примечание: Есть ча То, что я предполагаю, что перекрывающиеся строки означают, что меньшая строка полностью инкапсулирована внутри большей. Для таких строк, как be right back, right back into для предложения I will be right back into this, аббревиатура от вашего сообщения не определена. Я полагаю, что эти ситуации не для вашего случая использования.

0 голосов
/ 05 февраля 2020

Ваша проблема здесь: вы проверяете только последний ответ. Смотрите мой встроенный комментарий ниже.


        for (String str : toCheck){
         if (dict.containsKey(str)){
                s = s.replace(str, dict.get(str));
                System.out.println(s);
          }
        }

        return s;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...