简体   繁体   English

字符串中的最后一个重复字符

[英]Last repeating character in a string

I am searching for a solution to find the last repeating character in a string which says "how are you doing today", which supposed to give y as the answer. 我正在寻找一种解决方案,以找到字符串中最后一个重复的字符,该字符串显示“您今天好吗”,应该以y作为答案。 I have tried using Linked Hash Map to get the ordered insertions, but I am getting d as the last repeated one. 我尝试使用链接哈希映射来获取有序的插入,但是我将d作为最后重复的插入。

String testString  =  "how are you doing today";

    char[] testStringArray = testString.toCharArray();
    Map<Character,Integer> map = new LinkedHashMap<>();

    for( char i : testStringArray) {
     if (!(i==' ')) {
    if(map.containsKey(i) ) {
        map.put(i, map.get(i)+1);
    } else {
        map.put(i, 1);
    }
     }
    }

    System.out.println(map);

    List<Entry<Character, Integer>> list = new ArrayList<>(map.entrySet());
    ListIterator<Entry<Character, Integer>> it = list.listIterator(list.size());    

    while(it.hasPrevious()) {
        if(it.previous().getValue() > 1)
            System.out.println(it.previous().getKey());


    }
}

Help is appreciated. 感谢帮助。

This code scans from last character and checks if it's present in the remaining substring before first character: 此代码从最后一个字符开始扫描,并检查它是否存在于第一个字符之前的其余子字符串中:

String str = "how are you doing today";
int len = str.length();
int i = len - 1;
for (; i >= 1; i--) {
    if (str.substring(0, i).contains(str.charAt(i) + "")) {
        break;
    }
}
if (i == 0) {
    System.out.println("no repeating character");
} else
    System.out.println(str.charAt(i));

You can use a simple method which uses a Set . 您可以使用使用Set的简单方法。 Keep adding the elements to the Set after reading them from the String's char array (use toCharArray() ), if the returned value of the add() operation is false, it means that the element was already added. 从String的char数组中读取元素后,请继续将其添加到Set (使用toCharArray() ),如果add()操作的返回值为false,则意味着该元素已被添加。 Keep a char variable that contains the "latest last element" . 保留一个包含“最新的最后一个元素”的char变量。 Just print it when the loop ends. 只需在循环结束时打印即可。

A simple solution is to iterate through the characters backwards, and use lastIndexOf to find the previous position of that character: 一个简单的解决方案是向后遍历字符,并使用lastIndexOf查找该字符的先前位置:

for (int i = testString.length() - 1; i > 0; --i) {
  char ch = testString.charAt(i);
  if (testString.lastIndexOf(ch, i - 1) != -1) {
    return ch;
  }
}
// Handle no repeating character found.

That is happening because LinkedHashMap is maintaining the addition order and y is getting inserted before d for given string and when you iterate from last it reads d first. 发生这种情况是因为LinkedHashMap保持加法顺序,并且y在给定字符串的d之前插入,并且当您从最后一次进行迭代时,它首先读取d

In order to achieve what you want i would suggest 为了实现你想要的,我建议

  1. Reading your string from end and then insert in LinkedHashMap with count 从末尾读取您的字符串,然后将count插入LinkedHashMap中
  2. Iterate LinkedHashMap from start to get the desired output. 从开始迭代LinkedHashMap以获得所需的输出。

Hope this helps. 希望这可以帮助。

This code you could use ArrayList or Set instead of LinkedHashMap, there is no need. 您可以使用ArrayList或Set代替LinkedHashMap来使用此代码,没有必要。 Here is my code : 这是我的代码:

public static Character getLastRepeatingCharacter(String src) {
    Character defaultChar = null;
    char[] srcCharArr = src.toCharArray();
    List<Character> list = new ArrayList<Character>();
    final int length = srcCharArr.length;
    for(int idx = 0; idx < length; idx++) {
        if (srcCharArr[idx] == ' ') {
            continue;
        }
        if (list.contains(srcCharArr[idx])) {
            defaultChar = srcCharArr[idx];
        }else {
            list.add(srcCharArr[idx]);
        }
    }
    if (list.size() == length) {
        defaultChar = srcCharArr[length-1];
    }
    return defaultChar;
}

There are two bugs in the code that you posted: 1) ordering in LinkedHashMap , and 2) calling previous() twice in your iterator loop. 您发布的代码中有两个错误:1)在LinkedHashMap排序,以及2)在迭代器循环中两次调用previous()

To get the order you want from LinkedHashMap , you want insertion order. 要从LinkedHashMap获得所需的顺序,您需要插入顺序。 But updating a value already in the map does not change the insertion order. 但是更新映射中已经存在的值不会更改插入顺序。 From the specification : 规格

Note that insertion order is not affected if a key is re-inserted into the map. 请注意,如果将密钥重新插入到映射中,则插入顺序不会受到影响。 (A key k is reinserted into a map m if m.put(k, v) is invoked when m.containsKey(k) would return true immediately prior to the invocation.) (如果在调用之前m.containsKey(k)将立即返回true时调用了m.put(k,v),则将密钥k重新插入到映射m中。)

To get around this, you have to remove the entry and insert it again. 要解决此问题,您必须删除条目并再次插入。 Instead of: 代替:

    map.put(i, map.get(i) + 1);

you have to do: 你必须做:

    int old = map.get(i);
    map.remove(i);
    map.put(i, old + 1);

The second problem is that you call previous() twice in the iterator loop that's iterating backwards. 第二个问题是,您在向后迭代的迭代器循环中调用了previous()两次。 This has the side effect advancing the iterator again after you've found the entry you want. 找到所需条目后,这会产生副作用,即再次推进迭代器。 You need to cache the result of previous() and use it twice. 您需要缓存previous()的结果并使用两次。 So, instead of: 因此,代替:

    while (it.hasPrevious()) {
        if (it.previous().getValue() > 1)
            System.out.println(it.previous().getKey());
    }

you need to do: 您需要执行以下操作:

    while (it.hasPrevious()) {
        Entry<Character, Integer> prev = it.previous();
        if (prev.getValue() > 1)
            System.out.println(prev.getKey());
    }

(I suspect you might have found and fixed this one already, because with this fix in place, but not the LinkedHashMap fix, the result is d which matches what you see.) (我怀疑您可能已经找到并修复了此问题,因为有了此修复程序,但没有LinkedHashMap修复程序,结果是d与您所看到的匹配。)

Fundamentally, I think you're taking the right approach. 从根本上讲,我认为您采用的是正确的方法。 Essentially, it's this: 本质上是这样的:

  1. generate a histogram of the frequency of characters' occurrences in the string; 生成字符串中字符出现频率的直方图; and then 接着
  2. iterate backwards to find the last character whose frequency is greater than 1, meaning it's a repeat. 向后迭代以找到频率大于1的最后一个字符,这意味着它是重复的。

A simplifying variation is to iterate backward getting characters from the string, and looking in the map to find the first one whose frequency is > 1. The string maintains the order, so the map doesn't have to. 一种简化的变体是迭代从字符串中向后获取字符,然后在映射中查找以找到频率大于1的第一个字符字符串保持顺序,因此映射不必如此。 You can thus avoid using LinkedHashMap and the extra work necessary to maintain its insertion order. 因此,您可以避免使用LinkedHashMap和维护其插入顺序所需的额外工作。 You'd do something like this: 您将执行以下操作:

    for (int i = testString.length() - 1; i >= 0; i--) {
        char ch = testString.charAt(i);
        if (map.containsKey(ch) && map.get(ch) > 1) {
            System.out.println(ch);
        }
    }

It turns out that there are even simpler ways to do both of these using Java 8 lambdas and streams. 事实证明,使用Java 8 lambda和流可以使用更简单的方法来完成这两种操作。 First, to generate a histogram (frequency map) of the occurrence of characters, given a string input , do this: 首先,在给定字符串input的情况下,生成字符出现的直方图(频率图),请执行以下操作:

    Map<Character, Long> hist =
        input.chars()
             .mapToObj(ch -> (char)ch)
             .filter(ch -> ch != ' ')
             .collect(groupingBy(ch -> ch, counting()));

The wrinkle here is that the chars() method returns an IntStream with each char value contained in an int . 这里的皱纹是, chars()方法返回一个IntStream与每个char包含在值int Thus, you have to cast to char within mapToObj() in order to turn this into a Stream<Character> . 因此,必须将其转换为mapToObj()中的char才能将其转换为Stream<Character> Note that I'm relying on static import of java.util.stream.Collectors.* to get the concise grouping/counting collector. 请注意,我依赖于java.util.stream.Collectors.*静态导入来获取简洁的分组/计数收集器。

Once you have the histogram, you can stream over the chars again and use a reduce() trick to get the last element: 获得直方图后,就可以再次串流字符,并使用reduce()技巧获取最后一个元素:

           input.chars()
                .mapToObj(ch -> (char)ch)
                .filter(ch -> ch != ' ')
                .filter(ch -> hist.get(ch) > 1L)
                .reduce((a, b) -> b);

Putting it all together, you have this: 放在一起,您将拥有:

Optional<Character> lastRepeat(String input) {
    Map<Character, Long> hist =
        input.chars()
             .mapToObj(ch -> (char)ch)
             .filter(ch -> ch != ' ')
             .collect(groupingBy(ch -> ch, counting()));
    return input.chars()
                .mapToObj(ch -> (char)ch)
                .filter(ch -> ch != ' ')
                .filter(ch -> hist.get(ch) > 1L)
                .reduce((a, b) -> b);
}

This returns an Optional containing the last repeated character in the string, or an empty Optional if there are no repeated characters. 这将返回一个Optional其中包含字符串中的最后一个重复的字符;如果没有重复的字符,则返回一个空的Optional

    String str="how are you doing today";


    char charArr[]=str.toCharArray();

    HashMap<Character,Integer> hMap=new HashMap();


    for(int i=0;i<charArr.length;i++)
    {
        if(hMap.containsKey(charArr[i]))
        {
            int count=hMap.get(charArr[i]);
            hMap.put(charArr[i],count+1);
        }else
        {
            hMap.put(charArr[i], 1);
        }
    }
    System.out.println(hMap);
    for(int i=charArr.length-1;i>=0;i--)
    {
        if(hMap.get(charArr[i])>1)
        {
            System.out.println("The Last Repeated Character is :"+charArr[i]);
            break;
        }
    }

Output: 输出:

    { =4, a=2, d=2, e=1, g=1, h=1, i=1, n=1, o=4, r=1, t=1, u=1, w=1, y=2}

    The Last Repeated Character is : y

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

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