【问题标题】:Algorithm seems to only work on last chunk of ArrayList算法似乎只适用于 ArrayList 的最后一块
【发布时间】:2014-11-27 08:19:50
【问题描述】:

这个算法的目标是获取一个字符串列表并以这样一种方式缩写它们,以便它们可以唯一地识别它们所代表的单词,这是一个家庭作业。

我尝试过的算法为这个问题创建搜索子字符串以寻找任何可能的匹配项,虽然看起来 trie 对这个解决方案更有效,但我似乎无法理解代码的工作原理;话虽如此,这样做也应该很有可能。

输入:~~~~~~~~~~~~ 预期输出:~~~~~~~~~~~~ 实际输出:
碳水化合物 -------- 碳水化合物 -------------------------------- 碳水化合物
购物车 -------------------- 购物车 ---------------------------- -------- 购物车
化油器 ------------ carbu --------------------------------- 化油器
焦糖 --------------- 卡拉 --------------------------------- -- 焦糖
驯鹿 --------------- cari --------------------------------- ---- 驯鹿
碳酸 -------------- 碳酸 -------------------------------- 碳酸 软骨 -------------- 软骨 ---------------------- -- 软骨
碳 ---------------- 碳 -------------------------------- - 碳
马车 -------------- 马车 -------------------------------- carr 纸箱 ----------------- 纸箱 -------------------------------------------- ---- 卡托
汽车 --------- 汽车 ---------------------------- ---------- 车
碳酸盐 ------------ 碳酸盐 ------------------- 碳酸盐

这是实际代码。

import java.util.ArrayList;

public class ShortestPrefixes
{

    ArrayList<String> characterCounter = new ArrayList<>();
    boolean isEqual = false;

    public static ArrayList testArrayList()
    {
        ArrayList<String> testArray = new ArrayList<>();
        testArray.add("carbohydrate");
        testArray.add("cart");
        testArray.add("carburetor");
        testArray.add("caramel");
        testArray.add("caribou");
        testArray.add("carbonic");
        testArray.add("cartilage");
        testArray.add("carbon");
        testArray.add("carriage");
        testArray.add("carton");
        testArray.add("car");
        testArray.add("carbonate");
        return testArray;

    }
    public ArrayList getShortestPrefixes(ArrayList<String> input)
    {
        ArrayList<String> output = new ArrayList<>();
        System.out.println(input.size());
        for (int count = 0; count<input.size(); count++) //This loop counts which word is being reduced
        {
            //System.out.println(count);
            String word = input.get(count);
            //System.out.println(word);
            for (int compare = 0; compare<input.size(); compare++)//this loop counts the characters of the word being reduced
            {

                    if(input.get(compare) .equals(word)){}

                        isEqual=false;
                        ArrayList<String> wordBeingComparedRightNow = new ArrayList<>();
                        for (int searchCount = 0; searchCount<input.get(searchCount).length(); searchCount++)//this loop compares the string to every possible substring
                        {
                            wordBeingComparedRightNow.clear();
                            String wordAboutToBeCompared = input.get(searchCount);
                            wordBeingComparedRightNow.add(wordAboutToBeCompared);

                            for (int miniLoop = 0; miniLoop<input.get(searchCount).length()-1; miniLoop++)//this loop sets up for a word's substrings to be tested
                            {
                                wordAboutToBeCompared = wordAboutToBeCompared.substring(0, wordAboutToBeCompared.length() -1);
                                wordBeingComparedRightNow.add(wordAboutToBeCompared);

                            }

                            for(int variableName = 0; variableName < wordBeingComparedRightNow.size(); variableName++)//this word compares the array craeated in the last step with the substring we currently have
                            {
                                if(wordBeingComparedRightNow.get(variableName) .equals(word.substring(0, word.length()-1)))
                                {
                                    isEqual=true;
                                }

                            }
                        }
                            if (!isEqual)
                            {
                            System.out.println(word);
                            word = word.substring(0, word.length()-1);
                            }

            }
            //System.out.println(word);
            output.add(word);

        }

        System.out.println(testArrayList());
        return output;

    }

    public static void main(String[] args)
    {
        ShortestPrefixes sp = new ShortestPrefixes();
        ArrayList<String> output = sp.getShortestPrefixes(testArrayList());
        System.out.println(output);

    }

}

我认为问题出在第二个 for 循环中的某个地方,但我不太清楚在哪里;如果有人能确定我的算法为什么不起作用,或者至少能指出我正确的方向;我真的很感激。 谢谢。

【问题讨论】:

  • if(input.get(compare) .equals(word)){} 的目的是什么?
  • 你如何得到这个映射carbohydrate -------- carboh -------------------------------- carbohydrate 输入中没有你期望的 carboh?
  • if(input.get(compare) .equals(word){} 是我用来尝试通过强制循环继续()来调试我的代码的东西;但我在某些时候删除了它把它当作垃圾的点。

标签: java algorithm arraylist


【解决方案1】:

如果我能很好地理解您要做什么,那么对于每个单词,您都会尝试从最长的前缀开始找到最短的前缀。

然后检查下一个前缀(当前的一个减去一个字符)是否等于其他单词的所有可能子字符串中的一些。 注意,你也是在比较前缀和当前单词的子串,在这个比较中你需要跳过当前单词。

如果下一个前缀是唯一的,则它成为当前前缀:word.substring(0, word.length()-1) 应重复该过程,直到找不到唯一的较短前缀为止。

但是这个for很奇怪:

for (int searchCount = 0; searchCount < input.get(searchCount).length(); searchCount++)

您遍历searchCount,但它是结束条件双方的一部分。所以每次迭代的结束条件都不一样。

由于这是家庭作业,我将向您推荐另一种我认为更简单的方法。这个想法是从单字母前缀开始并扩大它们直到所有都有效。

Step 0:
    input <- [carbohydrate, cart, carburetor, caramel, caribou, carbonic, cartilage, carbon, carriage, carton, car, carbonate]
    output <- [ , , , , , , , , , , , ]

Step 1: 
    For each prefix in output check if it's valid. (*1) If not then add one more char to it. 

Step 2:   
    If some prefix was not valid, the go to step 1.

(*1) A prefix is valid if one of the folling conditions occurs: Prefix is unique in output or you cannot add more chars prefix == word

提示每次迭代的输出是:

Iteration 0: [, , , , , , , , , , , ]
Iteration 1: [c, c, c, c, c, c, c, c, c, c, c, c]
Iteration 2: [ca, ca, ca, ca, ca, ca, ca, ca, ca, ca, ca, ca]
Iteration 3: [car, car, car, car, car, car, car, car, car, car, car, car]
Iteration 4: [carb, cart, carb, cara, cari, carb, cart, carb, carr, cart, car, carb]
Iteration 5: [carbo, cart, carbu, cara, cari, carbo, carti, carbo, carr, carto, car, carbo]
Iteration 6: [carboh, cart, carbu, cara, cari, carbon, carti, carbon, carr, carto, car, carbon]
Iteration 7: [carboh, cart, carbu, cara, cari, carboni, carti, carbon, carr, carto, car, carbona]

试试看。我用一个小实现对其进行了测试。但由于这是家庭作业,我认为我不应该直接给你代码;)如果你遇到困难,发表评论。

伪代码

// Step 0: Initialize input and output

input <- [carbohydrate, cart, carburetor, caramel, caribou, carbonic, cartilage, carbon, carriage, carton, car, carbonate]
output <- [ , , , , , , , , , , , ]

allFound <- false; // Helper variable to know if all prefixes are valid

while (not allFound) { // Step 2 Iteration: until all prefixes are ok

    // For simplicity, we first count the occurrences of each prefix
    for each prefix in output {
        prefixCount[prefix] <- prefixCount[prefix] + 1 // You may use a Map for this 
    }

    // Step 1: For each prefix check if is valid, if not add one more char
    allFound <- true; 
    for (i = 0; i < output size; i++) {
        if not (prefixCount[prefix] == 1 /* is unique */ OR output[i] is equals input[i]) {
            // Prefix is not ok                
            output[i] <- output[i] + next char form input[i]; // Add one more char
            allFound <- false; // Step 2 iteration condition "some prefix is not valid"
        }       
    }   
}   

【讨论】:

  • 感谢您的快速回复和帮助,这正是我想要做的。我在尝试您的方法时遇到了问题,我不确定如何利用我的循环来达到预期的结果。我有一个循环输入数组列表中每个字符串的 for 循环,以及一个循环单个字符串的 while 循环。我只是不确定我应该做什么。
  • @Thraktor 编辑了我的答案。我已经简化了算法(当然可以优化)并添加了一个带有主要思想的伪代码。您只需要两个循环级别。
  • 我遇到了另一个问题,我认为我从伪代码中为每个循环编写的内容不起作用,我遇到了两种情况;数组 prefixCount 只是重复增加大小,或者每个值都设置为 1,这取决于我声明它的位置。我把它写成一个常规的 for 循环,因为我不确定 for 每个循环的语法。有问题吗?
  • For 每个循环本质上相当于一个常规的 for。那不是问题。看看这个实现ideone.com/ytznr6
  • 感谢您的帮助,我之前的问题是我误解了伪代码中“计算每个前缀的出现次数”的含义。
猜你喜欢
  • 2020-08-30
  • 1970-01-01
  • 2011-03-29
  • 2018-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多