【问题标题】:Finding and removing all duplicate in string unless they repeat an odd number of times查找并删除字符串中的所有重复项,除非它们重复奇数次
【发布时间】:2017-07-25 16:20:28
【问题描述】:

我已经尝试解决这个任务可能已经一个多小时了。 我需要从字符串中删除所有重复项,但棘手的部分是,如果一个字母重复且次数奇数,则该字母的一个副本应保留在最终字符串中。例如,字符串 assdafff 应转换为 df,因为 f 出现奇数次。我设法制作了一个程序来删除所有重复项,但我找不到在那里出现奇数次的那些。 重要的是要保持输出字符串中遇到的元素的顺序与输入中的相同。

 public static void main(String[] args){        
Scanner reader = new Scanner(System.in);
String x = reader.nextLine();
String ne = "";
StringBuffer buf = new StringBuffer(x.length() -1);
for(int i=0; i<x.length(); i++){
    for(int v = 0; v<x.length(); v++){
        if((x.charAt(i)==x.charAt(v))&&(i!=v)){
            break;
    }
    if((v==x.length()-1)&&(i!=v)){
        ne+=x.charAt(i);
    }}
}
if(ne.equals("")){
    System.out.println("Empty String");
}else{
System.out.println(ne);
}
}

【问题讨论】:

    标签: java string


    【解决方案1】:

    1 次迭代并使用 Map 来保持计数。

    2 再次迭代,只保留奇数的字符

    String string = "deadbeef";
    
    // ALL COUNTS
    Map<Character,Integer> counts=new HashMap<Character,Integer>();
    
    for(int i= 0; i< string.length(); i++)
        {
      char c = string.charAt(i);
    
      if (counts.containsKey(c))
        counts.put(c,counts.get(c)+1);  
      else
          counts.put(c, 1);
      }
    
    // RESULT
    String result="";
    
    // ALLREADY USED
    Set<Character> set=new HashSet<Character>();
    
    for(int i= 0; i< string.length(); i++)
        {
        char c = string.charAt(i);
    
            // ODD AND FIRST
          if ((counts.get(c)%2==1)
              &&(!set.contains(c)))
              result+=c;
    
         set.add(c);
        }   
    
    System.out.println("RESULT:"+result);  // => eabf
    

    【讨论】:

    • 什么是地图?我有使用单独的 for 循环来查找奇数重复项的想法,但最终的字符串应该具有字母的原始位置
    • docs.oracle.com/javase/7/docs/api/java/util/Map.html。你是初学者,不是吗?
    • 为什么这不起作用Map&lt;Character, Integer&gt; m = new HashMap&lt;Character, Integer&gt;();这是我定义的地图,我添加了元素但我不能用这个for (Integer key : m.values()) { if(key%2==0){ m.remove(key); } }删除它们
    • @Mik - 我完成了我的解决方案(使用 Map 和 Set)。其他解决方案也有效。 1 在您的代码中:您从值(整数)中获取键,但您使用它来删除 - 2 在您删除这样的键时您无法迭代。见stackoverflow.com/questions/6092642/…
    【解决方案2】:

    算法很简单。正如其他人所指出的那样,您可以将字符串中每个字符的计数存储在映射中,然后仅保留映射中奇数的条目。为了保留插入顺序,您应该使用LinkedHashMap。然后,我们将 map 的键合并成一个新的字符串。

    Java 8 解决方案可能如下:

    String string = "string-123-string";
    
    Map<Integer, Long> map = string.chars()
            .boxed()
            .collect(Collectors.groupingBy(
                    Function.identity(),
                    LinkedHashMap::new,
                    Collectors.counting()));
    
    map.values().removeIf(count -> count % 2 == 0);
    
    String result = map.keySet().stream()
            .map(i -> new char[] { (char) i.intValue() })
            .map(String::new)
            .collect(Collectors.joining());
    
    System.out.println(result); // 123
    

    【讨论】:

    • 当我测试这段代码时,eclipse 出现错误并给我未知错误prntscr.com/egw4be
    • @Mik 我相信这个错误是由于你的x 变量是null
    • 或者可能是因为代码没有编译,即你缺少LinkedHashMapimport语句,而且包名好像也有错误...是不是同名作为目录?无论如何,我测试了我的答案代码,一切正常。
    【解决方案3】:

    我会像其他答案所建议的那样使用 Map,但它的问题是它不会以有序的方式存储键/值对,因此我使用了两个 ArrayList 来存储字符及其等效计数. 这是一个可行的解决方案:

    String string = "thisisastring";
    
    StringBuffer buffer = new StringBuffer();
    ArrayList<Character> chars = new ArrayList<>();
    ArrayList<Integer> counts = new ArrayList<>();
    
    for(int i= 0; i< string.length(); i++)
    {
      char curChar = string.charAt(i);
      int charIndex;
      // if curChar already exists in chars, increment its count      
      if((charIndex = chars.indexOf(curChar))>-1) 
      {
        counts.set(charIndex, counts.get(charIndex)+1);
      }
      else // else add it to chars and add its count which is 1 to counts
      {
        chars.add(curChar);
        counts.add(1);
      }
    }
    
    for(int i= 0; i< chars.size(); i++)
      // if char count is odd, add it to the buffer
      if(counts.get(i)%2!=0)  
        buffer.append(Character.toString(chars.get(i)));
    
    System.out.println(buffer.toString()); // prints hisarng
    

    编辑:正如@Federico Peralta Schaffner 提到的,您也可以使用LinkedHashMap,如下所示:

    String string = "thisisastring";
    StringBuffer buffer = new StringBuffer();
    LinkedHashMap<Character, Integer> linkedHashMap = new LinkedHashMap<>();
    
    for(int i=0; i< string.length(); i++)
    {
      char curChar = string.charAt(i);
      linkedHashMap.put(curChar, linkedHashMap.containsKey(curChar)?linkedHashMap.get(curChar)+1:1);
    }
    
    for(Map.Entry<Character, Integer> entry : linkedHashMap.entrySet())
      if(entry.getValue()%2 !=0)
        buffer.append(entry.getKey());
    
    System.out.println(buffer.toString());  // prints hisarng
    

    【讨论】:

    • 您可以使用LinkedHashMap 来保持广告顺序
    • @FedericoPeraltaSchaffner 哦,是的,您是对的,感谢您的指出。
    • @FedericoPeraltaSchaffner 如果你不介意的话,我编辑了我的答案来说明你的建议^^
    【解决方案4】:

    您只需一次迭代即可解决此问题。首先,您需要保存第一次遇到的字符的位置。如果您再次遇到它们,请删除当前的和您之前遇到的。例如,您有

    s = "assdafff"
    

    对于所有第一次遇到的字符,您将它们保存为

    for(i = 0; i<s.length(); i++)
      if(dict.get(s[i]) == null) //
        dict[s[i]] = i; 
    

    还有

    else // which means it's duplicate
      delete both s[i] and s[dict.get(s[i])] from string
    

    并且不要忘记删除当前的地图条目。

    【讨论】:

    • 但是什么是 dict ?
    • 对不起,忘了说,字典和map是一样的数据结构。将它们视为数组,但索引可以是整数以外的任何内容。但是,您可以不使用数组。我很确定您可以使用dict[Character.getNumericValue('a')] = 0 而不是dict['a'] = 0。我希望这能成功
    • 这个问题是关于Java的,你提供了一个python解决方案^^这两种语言之间有很大的不同。
    猜你喜欢
    • 2010-10-19
    • 1970-01-01
    • 2016-03-03
    • 1970-01-01
    • 2021-06-06
    • 1970-01-01
    • 2019-04-16
    • 1970-01-01
    • 2020-02-04
    相关资源
    最近更新 更多