字符串

时间:2016-07-19 11:27:13

标签: java collections

我正在寻找一个解决方案,找到一个字符串中的最后一个重复字符,上面写着“你今天过得怎么样”,它应该给出y作为答案。我已经尝试使用Linked Hash Map来获取有序插入,但我得到的是最后一次重复插入。

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());


    }
}

非常感谢帮助。

7 个答案:

答案 0 :(得分:3)

此代码从最后一个字符开始扫描并检查它是否出现在第一个字符之前的剩余子字符串中:

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));

答案 1 :(得分:1)

您可以使用使用Set的简单方法。 从String的char数组中读取后,继续将元素添加到Set(使用toCharArray()),如果add()操作的返回值为false,则表示该元素已添加。保留一个char变量,其中包含&#34;最新的最后一个元素&#34; 。只需在循环结束时打印它。

答案 2 :(得分:1)

一个简单的解决方案是向后迭代字符,并使用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.

答案 3 :(得分:0)

这种情况正在发生,因为LinkedHashMap正在维护添加顺序,并且yd之前插入给定字符串,当您从上一次迭代时,它首先读取d

为了实现你想要的建议

  
      
  1. 从末尾读取字符串,然后使用count
  2. 插入LinkedHashMap   
  3. 从头开始迭代LinkedHashMap以获得所需的输出。
  4.   

希望这有帮助。

答案 4 :(得分:0)

这段代码可以使用ArrayList或Set代替LinkedHashMap,没有必要。这是我的代码:

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;
}

答案 5 :(得分:0)

您发布的代码中有两个错误:1)在LinkedHashMap中排序,以及2)在迭代器循环中调用previous()两次。

要从LinkedHashMap获取所需的订单,您需要广告订单。但是,更新地图中已有的值会更改广告订单。来自the specification

  

请注意,如果将键重新插入地图,插入顺序不会受到影响。 (如果m.containsKey(k)在调用之前立即返回true,则调用m.put(k,v)时,将密钥k重新插入到映射m中。)

要解决此问题,您必须删除该条目并再次插入。而不是:

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

你必须这样做:

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

第二个问题是你在向后迭代的迭代器循环中调用previous()两次。在您找到所需的条目后,这会产生副作用,从而再次推进迭代器。您需要缓存previous()的结果并使用它两次。所以,而不是:

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

你需要这样做:

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

(我怀疑你可能已经找到并修复了这个,因为有了这个修复程序,而不是LinkedHashMap修复程序,结果是d与你看到的匹配。)

从根本上说,我认为你采取了正确的方法。基本上,就是这样:

  1. 生成字符频率的直方图&#39;字符串中出现的;然后
  2. 向后迭代以找到频率大于1的最后一个字符,这意味着它是重复的。
  3. 简化的变化是向后迭代从字符串中获取字符,并在地图中查找频率为> 1的第一个字符。 1. 字符串维护订单,因此地图不必。因此,您可以避免使用LinkedHashMap以及维护其插入顺序所需的额外工作。你可以这样做:

        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);
            }
        }
    

    事实证明,有甚至更简单的方法可以使用Java 8 lambdas和stream来完成这两个方法。首先,在给定字符串input的情况下生成字符出现的直方图(频率图),执行以下操作:

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

    这里的皱纹是chars()方法返回IntStreamchar中包含每个int值。因此,您必须在char内投放到mapToObj()才能将其转换为Stream<Character>。请注意,我依靠静态导入java.util.stream.Collectors.*来获得简洁的分组/计数收集器。

    获得直方图后,您可以再次流式传输字符并使用reduce()技巧获取最后一个元素:

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

    总而言之,你有这个:

    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);
    }
    

    这将返回包含字符串中最后重复字符的Optional,如果没有重复字符,则返回空Optional

答案 6 :(得分:0)

    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;
        }
    }

输出:

    { =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