在字符串中查找第一个非重复字符

时间:2016-02-02 10:38:55

标签: java string

我正在编写一个方法来查找字符串中的第一个非重复字符。我在之前的stackoverflow问题中看到了这个方法

public static char findFirstNonRepChar(String input){
 char currentChar = '\0';
 int len = input.length();
 for(int i=0;i<len;i++){
    currentChar = input.charAt(i);
    if((i!=0) && (currentChar!=input.charAt(i-1)) && (i==input.lastIndexOf(currentChar))){
        return currentChar;
    }
 }
 return currentChar;
}

我想出了一个使用哈希表的解决方案,其中我有两个for循环(不是嵌套),其中我在一个循环中通过字符串进行交互,记下每个字母的出现(例如在apple中,a将有1,p会有2,等等)然后在第二个循环中我通过哈希表进行交互,看看哪个首先计数为1。与我提出的方法相比,上述方法有什么好处?我是Java的新手,确实有两个循环(不是嵌套)阻碍了时间的复杂性。这两种算法都应该有O(n)对吗?对于这个问题,还有比这两个解决方案更快,更少的空间复杂度算法吗?

28 个答案:

答案 0 :(得分:6)

当您询问您的代码是否来自O(n)时,我认为不是,因为在for循环中,您正在调用lastIndexOf,而最糟糕的情况是O(n)。所以它来自O(n^2)

关于你的第二个问题:有两个非嵌套的循环,也来自O(n)

如果假设输入字符串中包含非unicode字符,并且假设大写或小写字符不同,则以下操作将使用o(n)并支持从0到{{1}的所有ASCII代码}:

255

感谢 Konstantinos Chalkias 提示有关溢出的提示,如果您的输入字符串出现超过127个特定字符,则可以从{{1}更改public static Character getFirstNotRepeatedChar(String input) { byte[] flags = new byte[256]; //all is initialized by 0 for (int i = 0; i < input.length(); i++) { // O(n) flags[(int)input.charAt(i)]++ ; } for (int i = 0; i < input.length(); i++) { // O(n) if(flags[(int)input.charAt(i)] > 0) return input.charAt(i); } return null; } 数组的类型} flagsbyte[],以防止int[]类型溢出。

希望它会有所帮助。

答案 1 :(得分:4)

你展示的算法很慢:它会查找字符串中的每个字符,它基本上意味着每个字符都花费你的时间来检查字符串两次!巨大的时间损失。

最好的天真O(n)解决方案基本上按插入顺序保存所有字符(因此可以找到第一个)并将可变整数映射到它们。当我们完成分析时,我们会遍历所有条目并返回已注册的第一个字符并且计数为1.

您可以使用的字符没有限制。 AtomicInteger可以使用import java.util.concurrent.atomic.AtomicInteger

使用Java 8:

public static char findFirstNonRepChar(String string) {
    Map<Integer,Long> characters = string.chars().boxed()
            .collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()));
    return (char)(int)characters.entrySet().stream()
            .filter(e -> e.getValue() == 1L)
            .findFirst()
            .map(Map.Entry::getKey)
            .orElseThrow(() -> new RuntimeException("No unrepeated character"));
}

非Java 8等价物:

public static char findFirstNonRepChar(String string) {
  Map<Character, AtomicInteger> characters = new LinkedHashMap<>(); // preserves order of insertion.
  for (int i = 0; i < string.length(); i++) {
    char c = string.charAt(i);
    AtomicInteger n = characters.get(c);
    if (n == null) {
      n = new AtomicInteger(0);
      characters.put(c, n);
    }
    n.incrementAndGet();
  }
  for (Map.Entry<Character, AtomicInteger> entry: characters.entries()) {
    if (entry.getValue().get() == 1) {
      return entry.getKey();
    }
  }
  throw new RuntimeException("No unrepeated character");
}

答案 2 :(得分:2)

public class FirstNonRepeatCharFromString {

    public static void main(String[] args) {

        String s = "java";
        for(Character ch:s.toCharArray()) {
            if(s.indexOf(ch) == s.lastIndexOf(ch)) {
                System.out.println("First non repeat character = " + ch);
                break;
            }
        }
    }
}

答案 3 :(得分:2)

import java.util.LinkedHashMap;
import java.util.Map;

public class getFirstNonRep {

public static char get(String s) throws Exception {
    if (s.length() == 0) {
        System.out.println("Fail");
        System.exit(0);
    } else {
        Map<Character, Integer> m = new LinkedHashMap<Character, Integer>();

        for (int i = 0; i < s.length(); i++) {
            if (m.containsKey(s.charAt(i))) {
                m.put(s.charAt(i), m.get(s.charAt(i)) + 1);
            } else {
                m.put(s.charAt(i), 1);
            }
        }
        for (Map.Entry<Character, Integer> hm : m.entrySet()) {
            if (hm.getValue() == 1) {
                return hm.getKey();
            }
        }
    }
    return 0;
}

public static void main(String[] args) throws Exception {

    System.out.print(get("Youssef Zaky"));

    }

 }

这个解决方案占用的空间更少,时间更少,因为我们只迭代字符串一次。

答案 4 :(得分:1)

我积累了字符串长度为25'500个符号的所有可能方法:

private static String getFirstUniqueChar(String line) {
    String result1 = null, result2 = null, result3 = null, result4 = null, result5 = null;
    int length = line.length();

    long start = System.currentTimeMillis();
    Map<Character, Integer> chars = new LinkedHashMap<Character, Integer>();
    char[] charArray1 = line.toCharArray();
    for (int i = 0; i < length; i++) {
        char currentChar = charArray1[i];
        chars.put(currentChar, chars.containsKey(currentChar) ? chars.get(currentChar) + 1 : 1);
    }
    for (Map.Entry<Character, Integer> entry : chars.entrySet()) {
        if (entry.getValue() == 1) {
            result1 = entry.getKey().toString();
            break;
        }
    }
    long end = System.currentTimeMillis();
    System.out.println("1st test:\n    result: " + result1 + "\n    time: " + (end - start));

    start = System.currentTimeMillis();
    for (int i = 0; i < length; i++) {
        String current = Character.toString(line.charAt(i));
        String left = line.substring(0, i);
        if (!left.contains(current)) {
            String right = line.substring(i + 1);
            if (!right.contains(current)) {
                result2 = current;
                break;
            }
        }
    }
    end = System.currentTimeMillis();
    System.out.println("2nd test:\n    result: " + result2 + "\n    time: " + (end - start));

    start = System.currentTimeMillis();
    for (int i = 0; i < length; i++) {
        char currentChar = line.charAt(i);
        if (line.indexOf(currentChar) == line.lastIndexOf(currentChar)) {
            result3 = Character.toString(currentChar);
            break;
        }
    }
    end = System.currentTimeMillis();
    System.out.println("3rd test:\n    result: " + result3 + "\n    time: " + (end - start));

    start = System.currentTimeMillis();
    char[] charArray4 = line.toCharArray();
    for (int i = 0; i < length; i++) {
        char currentChar = charArray4[i];
        int count = 0;
        for (int j = 0; j < length; j++) {
            if (currentChar == charArray4[j] && i != j) {
                count++;
                break;
            }
        }
        if (count == 0) {
            result4 = Character.toString(currentChar);
            break;
        }
    }
    end = System.currentTimeMillis();
    System.out.println("4th test:\n    result: " + result4 + "\n    time: " + (end - start));

    start = System.currentTimeMillis();
    for (int i = 0; i < length; i++) {
        char currentChar = line.charAt(i);
        int count = 0;
        for (int j = 0; j < length; j++) {
            if (currentChar == line.charAt(j) && i != j) {
                count++;
                break;
            }
        }
        if (count == 0) {
            result5 = Character.toString(currentChar);
            break;
        }
    }
    end = System.currentTimeMillis();
    System.out.println("5th test:\n    result: " + result5 + "\n    time: " + (end - start));

    return result1;
}

时间结果(5次):

1st test:
    result: g
    time: 13, 12, 12, 12, 14
2nd test:
    result: g
    time: 55, 56, 59, 70, 59
3rd test:
    result: g
    time: 2, 3, 2, 2, 3
4th test:
    result: g
    time: 3, 3, 2, 3, 3
5th test:
    result: g
    time: 6, 5, 5, 5, 6

答案 5 :(得分:1)

适用于任何类型的角色。

String charHolder;  // Holds 
String testString = "8uiuiti080t8xt8t";
char   testChar = ' ';
int count = 0;  

for (int i=0; i <= testString.length()-1; i++) {
    testChar = testString.charAt(i);

    for (int j=0; j < testString.length()-1; j++) {
        if (testChar == testString.charAt(j)) {
           count++;
        }
    }
    if (count == 1) { break; };
       count = 0;
}

System.out.println("The first not repeating character is " + testChar);

答案 6 :(得分:0)

   public static void firstNonRepeatFirstChar(String str) {

    System.out.println("The given string is: " + str);
    for (int i = 0; i < str.length(); i++) {
        boolean unique = true;
        for (int j = 0; j < str.length(); j++) {
            if (i != j && str.charAt(i) == str.charAt(j)) {
                unique = false;
                break;
            }
        }
        if (unique) {
            System.out.println("The first non repeated character in String is: " + str.charAt(i));
            break;
        }
    }
}

答案 7 :(得分:0)

  import java.util.*;
public class Main {
 public static void main(String[] args) {
  String str1 = "gibblegabbler";
  System.out.println("The given string is: " + str1);
  for (int i = 0; i < str1.length(); i++) {
   boolean unique = true;
   for (int j = 0; j < str1.length(); j++) {
    if (i != j && str1.charAt(i) == str1.charAt(j)) {
     unique = false;
     break;
    }
   }
   if (unique) {
    System.out.println("The first non repeated character in String is: " + str1.charAt(i));
    break;
   }
  }
 }
}

答案 8 :(得分:0)

public class GFG {
public static void main(String[] args) {
    String s = "mmjjjjmmn";
    for (char c : s.toCharArray()) {
        if (s.indexOf(c) == s.lastIndexOf(c)) {
            System.out.println("First non repeated is:" + c);
            break;
        }
    }
}

output = n

答案 9 :(得分:0)

Java中非重复的字符串

public class NonRepeatedCharacter {
     public static void main(String[] args) {
        String s = "ffeeddbbaaclck";
        for (int i = 0; i < s.length(); i++) {
             boolean unique = true;
             for (int j = 0; j < s.length(); j++) {
                 if (i != j && s.charAt(i) == s.charAt(j)) {
                     unique = false;
                     break;
                 }
              }
             if (unique) {
                 System.out.println("First non repeated characted in String \""
                 + s + "\" is:" + s.charAt(i));
                 break;
             }
         }
     }
}
Output:
First non repeated characted in String "ffeeddbbaaclck" is:l

For More Details

答案 10 :(得分:0)

在此编码中,我使用字符串长度来查找第一个非重复字母。

 package com.string.assingment3;
    import java.util.Scanner;
   public class FirstNonRepetedChar {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.println("Enter a String : ");
        String str = in.next();
        char[] ch = str.toCharArray();
        int length = ch.length;
        int x = length;
        for(int i=0;i<length;i++) {
            x = length-i;
            for(int j=i+1;j<length;j++) {
                if(ch[i]!=ch[j]) {
                    x--;
                }//if
            }//inner for
            if(x==1) {
            System.out.println(ch[i]);
                break;
            }
            else {
                    continue;
            }
        }//outer for
    }
}// develope by NDM

答案 11 :(得分:0)

在科特林

 fun firstNonRepeating(string: String): Char?{
    //Get a copy of the string
    var copy = string
    //Slice string into chars then convert them to string
    string.map { it.toString() }.forEach {
        //Replace first occurrance of that character and check if it still has it
        if (copy.replaceFirst(it,"").contains(it))
        //If it has the given character remove it
            copy = copy.replace(it,"")
    }
    //Return null if there is no non-repeating character
    if (copy.isEmpty())
        return null
    //Get the first character from what left of that string
    return copy.first()
}

https://pl.kotl.in/KzL-veYNZ

答案 12 :(得分:0)

String a = "sampapl";
    char ar[] = a.toCharArray();

    int dya[] = new int[256];
    for (int i = 0; i < dya.length; i++) {
        dya[i] = -1;
    }

    for (int i = 0; i < ar.length; i++) {

        if (dya[ar[i]] != -1) {
            System.out.println(ar[i]);
           break;
        } else {
            dya[ar[i]] = ar[i];
        }
    }

答案 13 :(得分:0)

使用Set与single for循环

公共静态字符firstNonRepeatedCharacter(String str){

Character result = null;

if (str != null) {
  Set<Character> set = new HashSet<>();
  for (char c : str.toCharArray()) {
    if (set.add(c) && result == null) {
      result = c;
    } else if (result != null && c == result) {
      result = null;
    }
  }
}
return result;

}

答案 14 :(得分:0)

您可以使用LinkedHashSet在String的单个遍历中实现此目标,如下所示:

react-native

答案 15 :(得分:0)

对于Java;

char firstNotRepeatingCharacter(String s) {
    
    HashSet<String> hs = new HashSet<>();
    StringBuilder sb =new StringBuilder(s);
    
    for (int i = 0; i<s.length(); i++){
        char c = sb.charAt(i);
        if(s.indexOf(c) == i && s.indexOf(c, i+1) == -1 ) {
            return c;
        }
    }

    return '_';
}

答案 16 :(得分:0)

list1 = ['abc', 'def', [['abc', 'def']], ['abc', 'def']]
[x[::-1] for x in list1][::-1]
# and got output as [['def', 'abc'], [['abc', 'def']], 'fed', 'cba']

答案 17 :(得分:0)

这是python中的解决方案:

input_str = "interesting"
#input_str = "aabbcc"
#input_str = "aaaapaabbcccq"


def firstNonRepeating(param):
    counts = {}        
    for i in range(0, len(param)):

    # Store count and index repectively
        if param[i] in counts:
            counts[param[i]][0] += 1
        else:
            counts[param[i]] = [1, i]

    result_index = len(param) - 1
    for x in counts:
        if counts[x][0] == 1 and result_index > counts[x][1]:
            result_index = counts[x][1]
    return result_index

result_index = firstNonRepeating(input_str)
if result_index == len(input_str)-1:
    print("no such character found")
else:
    print("first non repeating charater found: " + input_str[result_index])

输出:

first non repeating charater found: r

答案 18 :(得分:0)

char firstNotRepeatingCharacter(String s) {
    for(int i=0; i< s.length(); i++){
        if(i == s.lastIndexOf(s.charAt(i)) && i == s.indexOf(s.charAt(i))){
            return s.charAt(i);
        }
    }
    return '_';
}

答案 19 :(得分:0)

此解决方案的约束:

O(n)时间复杂度。我的解决方案是O(2n),遵循时间复杂度分析,O(2n)=&gt;为O(n)

import java.util.HashMap;

public class FindFirstNonDuplicateCharacter {
    public static void main(String args[]) {
    System.out.println(findFirstNonDuplicateCharacter("abacbcefd"));
    }

    private static char findFirstNonDuplicateCharacter(String s) {
    HashMap<Character, Integer> chDupCount = new HashMap<Character, Integer>();
    char[] charArr = s.toCharArray();
    for (char ch: charArr) { //first loop, make the tables and counted duplication by key O(n)
      if (!chDupCount.containsKey(ch)) {
        chDupCount.put(ch,1);
        continue;
      }
      int dupCount = chDupCount.get(ch)+1;
      chDupCount.replace(ch, dupCount);
    }

    char res = '-';
    for(char ch: charArr) { //second loop, get the first duplicate by count number, O(2n)
      // System.out.println("key: " + ch+", value: " + chDupCount.get(ch));
      if (chDupCount.get(ch) == 1) {
        res = ch;
        break;
      }
    }

    return res;
    } 
}

希望有所帮助

答案 20 :(得分:0)

几行代码对我有用。

public class FirstNonRepeatingCharacter {

    final static String string = "cascade";

    public static void main(String[] args) {

        char[] charArr = string.toCharArray();

        for (int i = 0; charArr.length > i; i++) {
            int count = 0;
            for (int j = 0; charArr.length > j; j++) {
                if (charArr[i] == charArr[j]) {
                    count++;
                }
            }
            if (count == 1){
                System.out.println("First Non Repeating Character is: " + charArr[i]);
                break;
            }
        }

    }
}

答案 21 :(得分:0)

由于LinkedHashMap保持插入顺序

package com.company;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {
    public static void main(String[] argh) {
        Scanner sc = new Scanner(System.in);
        String l = sc.nextLine();
        System.out.println(firstCharNoRepeated(l));
    }

    private static String firstCharNoRepeated(String l) {
        Map<String, Integer> chars = new LinkedHashMap();
        for(int i=0; i < l.length(); i++) {
            String c = String.valueOf(l.charAt(i));
            if(!chars.containsKey(c)){
                chars.put(c, i);
            } else {
                chars.remove(c);
            }
        }
        return chars.keySet().iterator().next();
    }
}

答案 22 :(得分:0)

public char firstNonRepeatedChar(String input) {
    char out = 0;
    int length = input.length();
    for (int i = 0; i < length; i++) {
        String sub1 = input.substring(0, i);
        String sub2 = input.substring(i + 1);
        if (!(sub1.contains(input.charAt(i) + "") || sub2.contains(input
                .charAt(i) + ""))) {
            out = input.charAt(i);
            break;
        }
    }
    return out;
}

答案 23 :(得分:0)

如果您只对a-z范围内的字符感兴趣(注释中请求OP的小写字母),则可以使用此方法,即每个字符需要最少2位的额外存储空间与HashMap方法相比。

/*
 * It works for lowercase a-z
 * you can scale it to add more characters
 * eg use 128 Vs 26 for ASCII or 256 for extended ASCII 
 */
public static char getFirstNotRepeatedChar(String input) {

    boolean[] charsExist = new boolean[26];
    boolean[] charsNonUnique = new boolean[26];

    for (int i = 0; i < input.length(); i++) {
        int index = 'z' - input.charAt(i);
        if (!charsExist[index]) {
            charsExist[index] = true;
        } else {
            charsNonUnique[index] = true;
        }
    }

    for (int i = 0; i < input.length(); i++) {
        if (!charsNonUnique['z' - input.charAt(i)])
            return input.charAt(i);
    }

    return '?'; //example return of no character found
}

答案 24 :(得分:0)

在两个循环(非嵌套)的情况下,时间复杂度为O(n)。

问题中提到的第二个解决方案可以实现为:

我们可以使用字符串字符作为地图的键并保持其计数。以下是算法。

1.从左到右扫描字符串并构建计数图。

2.再次,从左到右扫描字符串并检查地图中每个字符的计数,如果找到一个数字为1的元素,则将其返回。

package com.java.teasers.samples;  
import java.util.Map;  
import java.util.HashMap;  
public class NonRepeatCharacter {  
    public static void main(String[] args) {  
        String yourString = "Hi this is javateasers";//change it with your string  
        Map<Character, Integer> characterMap = new HashMap<Character, Integer>();  
        //Step 1 of the Algorithm  
        for (int i = 0; i < yourString.length(); i++) {  
            Character character = yourString.charAt(i);  
            //check if character is already present  
            if(null != characterMap.get(character)){  
                //in case it is already there increment the count by 1.  
                characterMap.put(character, characterMap.get(character) + 1);  
            }  
            //in case it is for the first time. Put 1 to the count  
            else  
                characterMap.put(character, 1);  
        }  
        //Step 2 of the Algorithm  
        for (int i = 0; i < yourString.length(); i++) {  
            Character character = yourString.charAt(i);  
            int count = characterMap.get(character);  
            if(count == 1){  
                System.out.println("character is:" + character);  
                break;  
            }  
        }  
    }  
}  

答案 25 :(得分:0)

好的,我最初误解了这个问题,所以这是一个新的解决方案。我相信这是O(n)。 contains(Object)的{​​{1}}是O(1),因此我们可以利用它并避免第二个循环。基本上,如果我们之前从未见过特定的HashSet,我们会将其添加到char作为潜在的候选人返回。然而,我们再次看到它,我们将其添加到validChars的垃圾箱中。这可以防止再次添加char。在循环结束时(无论您做什么, 至少循环一次),您将拥有invalidChars个散列集,其中validChars元素数量为n 。如果没有,那么它将从Character类返回null。这具有明显的优势,因为char类没有好的方法来回归“坏”。结果可以这么说。

public static Character findNonRepeatingChar(String x)
{
    HashSet<Character> validChars = new HashSet<>();
    HashSet<Character> invalidChars = new HashSet<>(); 

    char[] array = x.toCharArray();
    for (char c : array)
    {
        if (validChars.contains(c))
        {
            validChars.remove(c);
            invalidChars.add(c);
        }
        else if (!validChars.contains(c) && !invalidChars.contains(c))
        {
            validChars.add(c);
        }
    }

    return (!validChars.isEmpty() ? validChars.iterator().next() : null);
}

答案 26 :(得分:-1)

package com.test.util;

public class StringNoRepeat {

    public static void main(String args[]) {
        String st = "234123nljnsdfsdf41l";
        String strOrig=st;
        int i=0;
        int j=0;
        String st1="";
        Character ch=' ';
        boolean fnd=false;
        for (i=0;i<strOrig.length(); i++) {


            ch=strOrig.charAt(i);
            st1 = ch.toString();

            if (i==0)
                st = strOrig.substring(1,strOrig.length());
            else if (i == strOrig.length()-1)
            st=strOrig.substring(0, strOrig.length()-1);
            else 
                st=strOrig.substring(0, i)+strOrig.substring(i+1,strOrig.length());
            if (st.indexOf(st1) == -1) {
                fnd=true;
              j=i;
                break;  
            }
        }
        if (!fnd)
            System.out.println("The first no non repeated character");
        else
            System.out.println("The first non repeated character is " +strOrig.charAt(j));


    }

}

答案 27 :(得分:-1)

import java.util.Scanner;

public class NonRepaeated1
{
  public static void main(String args[])
  {
    String str;
    char non_repeat=0;
    int len,i,j,count=0;

    Scanner s = new Scanner(System.in);
    str = s.nextLine();

    len = str.length();

    for(i=0;i<len;i++) 
    { 
      non_repeat=str.charAt(i); 
      count=1; 

      for(j=0;j<len;j++) 
      { 
        if(i!=j) 
        { 
          if(str.charAt(i) == str.charAt(j)) 
          { 
            count=0; 
            break; 
          } 
        } 
      } 

      if(count==1) 
        break; 
    } 
if(count == 1) 
System.out.print("The non repeated character is  : " + non_repeat); 

  }
}