简体   繁体   English

字符串数组中的第一个唯一字符串

[英]First Unique String in an String array

Given a String Array how would you find the first unique String element in the array给定一个字符串数组,你如何找到数组中第一个唯一的字符串元素

public static String UniqueString(String[] s) {

    String str ="";

        for(int i=0;i<s.length;i++) {
            for(int j=i+1;j<s.length;j++) {
                System.out.println(s[i]+" "+s[j]);
                str = s[i];
                if(str==s[j]) {
                   break;
                }

                }if(!(str==s[i+1])){
                    return str;
                }

    }

    return str;
    }

so a String array of {Dog,Cat,Dog,Wolf,lion} would return as Cat所以 {Dog,Cat,Dog,Wolf,lion} 的字符串数组将返回为 Cat

Your approach grows quadratically with the size of the list.您的方法随着列表的大小呈二次方增长。 There's a better approach that is essentially linear in the list size, which is to use an ordered map from strings to the number of occurrences.有一种更好的方法,它基本上与列表大小呈线性关系,即使用从字符串到出现次数的有序映射。 Use one pass through the list to build the map and then one pass through the map to find the first element (if any) with a count of 1. You can use a LinkedHashMap to implement this.使用一次遍历列表来构建地图,然后一次遍历地图以找到计数为 1 的第一个元素(如果有)。您可以使用LinkedHashMap来实现这一点。

public static String uniqueString(String[] list) {
    Integer ZERO = 0; // to avoid repeated autoboxing below
    final LinkedHashMap<String, Integer> map = new LinkedHashMap<>(list.size());

    // build the map
    for (String s : list) {
        Integer count = map.getOrDefault(s, ZERO);
        map.put(s, count + 1);
    }

    // find the first unique entry. Note that set order is deterministic here.
    for (Set.Entry<String, Integer> entry : map.entrySet()) {
        if (entry.getValue() == 1) {
            return entry.getKey();
        }
    }

    // if we get this far, there was no unique string in the list
    return "";
}

Note that you could use any kind of Map implementation (including HashMap ) and forgo the ordering property of LinkedHashMap by replacing the second loop with a loop through the original list:请注意,您可以使用任何类型的Map实现(包括HashMap )并通过将第二个循环替换为原始列表的循环来放弃LinkedHashMap的排序属性:

for (String s : list) {
    if (map.get(s) == 1) {
        return s;
    }
}

However, if the list has lots of repeated strings then iterating through the map will probably require significantly fewer iterations.但是,如果列表有很多重复的字符串,那么遍历地图可能需要的迭代次数会少得多。 So might as well use the added functionality of LinkedHashMap , which you get for very little performance penalty compared to HashMap .所以不妨使用LinkedHashMap的附加功能,与HashMap相比,您获得的性能损失很小。

You were very close to a working solution, you need a flag to indicate whether you found the String again in s (not sure where you got names ).您非常接近工作解决方案,您需要一个标志来指示您是否在s再次找到了String (不确定您从哪里得到names )。 Also we compare String (s) with .equals (not == ).我们.equals String (s) 与.equals (不是== )进行比较。 And method names start with a lower case letter.方法名称以小写字母开头。 Something like,就像是,

public static String uniqueString(String[] s) {
    for (int i = 0; i < s.length; i++) {
        boolean unique = true;
        for (int j = i + 1; j < s.length; j++) {
            if (s[j].equals(s[i])) {
                s[j] = s[s.length - 1]; // <-- handle bug, ensure that dupes aren't
                                        // found again.
                unique = false;
                break;
            }
        }
        if (unique) {
            return s[i];
        }
    }
    return "";
}

Java 8爪哇 8

public static String uniqueString(String[] s) {
    StringBuilder result = new StringBuilder();
    Stream.of(s)
            .collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()))
            .entrySet()
            .stream()
            .filter(entry -> entry.getValue() == 1)
            .findFirst()
            .ifPresent(entry -> result.append(entry.getKey()));
    return result.toString();
}

Update , after 2 years: 2年后更新

Not sure why I had used a StringBuilder when I could just do it all in a single statement:不知道为什么我使用 StringBuilder 当我可以在一个语句中完成所有操作时:

public static String uniqueString(String[] s) {
    return Stream.of(s)
            .collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()))
            .entrySet()
            .stream()
            .filter(entry -> entry.getValue() == 1)
            .findFirst()
            .map(Map.Entry::getKey)
            .orElse(null);
}

Perhaps there is another solution that can also solve your problem in a more java-8 way:也许还有另一种解决方案也可以以更 java-8 的方式解决您的问题:

  1. using a map to record the count of the duplicated strings and then使用map记录重复字符串的数量,然后
  2. directly traverse the array from the very beginning till the end and从头到尾直接遍历数组
  3. once the string is not duplicated, we get it right there.一旦字符串没有重复,我们就在那里得到它。

That could be like:那可能是这样的:

public static void main(String... args) {
    String[] arr = {"Dog", "Cat", "Dog", "Wolf", "lion"};
    Map<String, Long> stringCountMap = Arrays.stream(arr)
            .collect(Collectors.groupingBy(s -> s, Collectors.counting()));
    for (String s : arr) {
        if (stringCountMap.get(s) == 1) {
            System.out.println("The first non-duplicate string: " + s);
            break;
        }
    }
}

Also you can turn to LinkedHashMap as others mentioned to keep the order to avoid traverse the original array again as:您也可以像其他人提到的那样转向LinkedHashMap以保持顺序以避免再次遍历原始数组:

private static void another(String[] arr) {
    Map<String, Long> stringCountMap = Arrays.stream(arr)
            .collect(Collectors.groupingBy(s -> s, LinkedHashMap::new, Collectors.counting()));
    for (String s : stringCountMap.keySet()) {
        if (stringCountMap.get(s) == 1) {
            System.out.println("The first non-duplicate string: " + s);
            break;
        }
    }
}

The output will always be:输出将始终为:

The first non-duplicate string: Cat

The above answer does not work in all cases.上述答案并不适用于所有情况。 for instance {"Dog","Dog",Cat} would return dog.例如 {"Dog","Dog",Cat} 将返回狗。 the problem being that It does not check the entire array for duplicates.问题是它不会检查整个数组是否有重复项。

private static String getFirstUniqueString(String[] names) {
    for(int x=0;x<names.length;x++)
    {
        if(countOccurences(names[x],names) == 1 )
            return names[x];
    }
    return "No Unique Strings";
}

private static int countOccurences(String string, String[] names) 
{
    int count=0;
    for(int y = 0; y<names.length;y++)
    {
        if(names[y].equals(string))
        {
            count++;
            if(count >1 )
                return count;
        }
    }
    return count;
}

Instead maybe break it into two pieces.相反,也许把它分成两部分。 One method to find the unique string the other to count occurrences this way we count exactly how many times the word is mentioned through the entire array.一种方法是找到唯一字符串,另一种方法是通过这种方式计算出现次数,我们准确计算整个数组中提到该单词的次数。 If you simply want to know there more then one and you want to save run time, uncomment the if statement.如果您只是想了解更多信息并且想节省运行时间,请取消对 if 语句的注释。

public static String FirstUniqueString(String[] strs) {
    List<String> list = new LinkedList<>();
    for (String s: strs) {
        if (list.contains(s)) {
            list.remove(s);
        } else {
            list.add(s);
        }
    }
    return list.get(0);
}

We can use a simple LinkedList to keep a track of the duplicates.我们可以使用一个简单的LinkedList来跟踪重复项。 For example, if the input is new String[] {Dog, Cat, Dog, Wolf, Lion, Dog} , the first unique element would still be Cat.例如,如果输入是new String[] {Dog, Cat, Dog, Wolf, Lion, Dog} ,第一个唯一元素仍然是 Cat。 The list after for-each loop will be in the following sequence: {Cat, Wolf, Lion, Dog} . for-each 循环后的列表将按以下顺序排列: {Cat, Wolf, Lion, Dog} Big O runtime will be O(N ^ 2) as the for-each loop and contains() requiring O(N) respectively. Big O 运行时将是 O(N ^ 2) 作为 for-each 循环和contains()分别需要 O(N)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM