如何解决这个 CodingBat 编码器问题?

How to solve this CodingBat encoder problem?

问题link:https://codingbat.com/prob/p238573

要求: 编写一个函数,将 raw 中的单词替换为 code_words 中的单词,这样 raw 中每个单词的第一次出现都分配给 code_words 中第一个未分配的单词。

编码器(["a"], ["1", "2", "3", "4"]) → ["1"]

编码器(["a", "b"], ["1", "2", "3", "4"]) → ["1", "2"]

编码器(["a", "b", "a"], ["1", "2", "3", "4"]) → ["1", "2", " 1"]

我尝试了两种不同的解决方案,但它仍然显示我的函数在“其他测试”中不起作用

第一个:

public String[] encoder(String[] raw, String[] code_words) {
          HashMap<String, String> hm = new HashMap<String, String>();
          for (int i=raw.length - 1; i >= 0; i--) {
              hm.put(raw[i], code_words[i]);
          }
            
          
          String [] finalarray = new String[raw.length];
          for (int i=0; i < raw.length; i++) {
            String x = hm.get(raw[i]);
            finalarray[i] = x;
          }
          return finalarray;
        }

所有测试都很好,但“其他测试”失败了

so I thought it was because of this line in requirements the first occurrence of each word in raw is assigned the first unassigned word in code_words

所以我将代码更新为:

public String[] encoder(String[] raw, String[] code_words) {
          HashMap<String, String> hm = new HashMap<String, String>();
          for (int i=0; i < raw.length; i++) {
            String word = raw[i];
            String value = code_words[i];
            if (!hm.containsKey(word)) {
                if (hm.containsValue(value)) {
                    for (int i1=0; i1 < code_words.length; i1++) {
                        value = code_words[i1];
                        if (!hm.containsValue(value)) {
                            hm.put(word, value);
                            break;
                        }
                    }
                
                }
                else {
                    hm.put(word, value);
                }
                
                }   
            }
          String[] finalarray = new String[raw.length];
          for (int i=0; i < raw.length; i++) {
              String x = hm.get(raw[i]);
              finalarray[i] = x;
          }
        return finalarray;
    }

但是失败了,我不知道为什么。

编辑: 我的(第二个)代码的问题是: 如果我们假设 raw = {"a", "a", "b", "d"} 和码字 = {"1", "2", "3", "4"}

我的代码会将字母“a”分配给“1”,将“b”分配给“3”,将 d 分配给“4” 即使它是第一个未分配的字母

,也会留下未分配的“2”

我提供的代码稍作调整

public String[] encoder(String[] raw, String[] code_words) {
          HashMap<String, String> hm = new HashMap<String, String>();
          for (int i=0; i < raw.length; i++) {
            String word = raw[i];
            int assigned = 0;
            String value = code_words[assigned];
            if (!hm.containsKey(word)) {
                if (hm.containsValue(value)) {
                    for (int i1=0; i1 < code_words.length; i1++) {
                        value = code_words[i1];
                        if (!hm.containsValue(value)) {
                            hm.put(word, value);
                            assigned++;
                            break;
                        }
                    }
                
                }
                else {
                    hm.put(word, value);
                    assigned++;
                }
                
                }   
            }
          String[] finalarray = new String[raw.length];
          for (int i=0; i < raw.length; i++) {
              String x = hm.get(raw[i]);
              finalarray[i] = x;
          }
        return finalarray;
    }

但使用下面提供的代码肯定更有效。感谢贡献者!

你让它变得比实际复杂得多。

是的,您需要 hm 映射,是的,只有当 raw 单词还不是映射中的键时才添加它。

但是要跟踪下一个未分配的 code_word,您只需要将 index 放入 code_words 数组。

Map<String, String> hm = new HashMap<>();
int unassigned = 0;
for (String word : raw) {
    if (! hm.containsKey(word)) {
        hm.put(word, code_words[unassigned]);
        unassigned++;
    }
}

整个方法的代码可以压缩为:

public String[] encoder(String[] raw, String[] code_words) {
    String[] encoded = new String[raw.length];
    Map<String, String> hm = new HashMap<>();
    for (int i = 0, unassigned = 0; i < raw.length; i++)
        if ((encoded[i] = hm.get(raw[i])) == null)
            hm.put(raw[i], encoded[i] = code_words[unassigned++]);
    return encoded;
}

问题

你的第一个想法还不错。问题是,您应该用 code_words.

中第一个未分配的单词替换 all 中出现的单词 raw

如何修复

让我们首先分析如何修复您的第一个代码。您使用 HashMap 的想法非常好。显然,如果 raw 的单词已经存在于 HashMap 中,您不想再次添加它,因此您只需在第一次迭代中跳过它。
现在,如果 ith word in raw has no assigned value in hashMap, you should add it the first unassigned word of code_words, which may have a与 i 不同的索引,所以我们给它分配另一个索引,比方说 j。之后,第j个词被赋值,第一个未赋值的词索引为j+1。
在像这样迭代一次 raw 之后,每个单词在你的 HashMap 中都有一个分配的代码,你可以再迭代一次并分配值。

代码

您的最终代码将如下所示:

public String[] encoder(String[] raw, String[] code_words) {
    HashMap<String, String> dictionary = new HashMap<>();
    String[] coded = new String[raw.length];
    int j = 0;
    for(int i = 0; i < raw.length; i++) {
        if(!dictionary.containsKey(raw[i])) { //if it has no assigned value
            dictionary.put(raw[i], code_words[j]); //add to hashmap
            j++; //set index to next unassigned
        }
        //do nothing if already found before
    }
    for(int i = 0; i < raw.length; i++) {
        coded[i] = dictionary.get(raw[i]); //get coded word and set in final array
    }
    return coded;
}

我们可以把这个写得更紧凑一些,有些人可能更喜欢这样,而另一些人可能会觉得更混乱,所以这取决于你。

public String[] encoder(String[] raw, String[] code_words) {
    HashMap<String, String> dictionary = new HashMap<>();
    String[] coded = new String[raw.length];
    int j = 0;
    for(int i = 0; i < raw.length; i++) {
        if(!dictionary.containsKey(raw[i])) { //if it has no assigned value
            dictionary.put(raw[i], code_words[j++]); //add to hashmap and also increment index of code_words
        }
        coded[i] = dictionary.get(raw[i]);
    }
    return coded;
}

最后一个代码通过了所有测试。

只更新一行

hm.put(raw[i], code_words[raw[i].charAt(0)-'a']);