【问题标题】:Linked Hash Map counter not properly incrementing链接哈希映射计数器未正确递增
【发布时间】:2022-01-25 11:44:42
【问题描述】:

尝试通过用数字替换重复字符来“压缩”字符串(例如,字符串 aabcccccaaa 将变为 a2blc5a3)。我尝试使用 Linked HashMap 来解决问题,因为需要保留输入顺序,但我创建的计数器似乎没有正确递增。任何见解将不胜感激。

public class StringCompression {
    
    public static void main(String[] args) {
        
        String s = "aabcccccaaa";
        System.out.println(compString(s));
        
    }
    
    public static String compString(String str) {
        
        LinkedHashMap <Character, Integer> alphabet = new LinkedHashMap<>();
        StringBuilder strbdr = new StringBuilder();     
        
        for(int i = 0; i < str.length(); i++) {
            
            if(alphabet.containsKey(str.charAt(i))) {
                alphabet.put(str.charAt(i), alphabet.get(str.charAt(i))+1);
            }
            
            alphabet.put(str.charAt(i), 1);
        }
        
//      System.out.println(alphabet.entrySet());
        
        for(var entry : alphabet.entrySet()) {
            strbdr.append(entry.getKey());
            strbdr.append(entry.getValue());
        }
        
        return strbdr.toString();
    }
}

【问题讨论】:

    标签: java string linkedhashmap


    【解决方案1】:

    如上所述,如果计算所有字符的频率,则需要基于地图的解决方案,但此任务类似于run-length encoding。

    值得一提的是,在每个单个字母之后添加频率1 似乎是多余的,因为在这种情况下字符串的长度加倍:abc -&gt; a1b1c1。

    另外,如果输入字符串包含其他数字,压缩后的字符串应该包含一些“转义”字符,以区分数字和计数。

    以下代码 sn-p 解决了上述问题:

    static String compress(String str) {
        if (null == str || str.isEmpty()) {
            return str;
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 0, n = str.length(); i < n; ) {
            char c = str.charAt(i);
            int count = 1;
            for (int j = i + 1; j < n && str.charAt(j) == c; j++) count++;
            if (Character.isDigit(c) || '~' == c) sb.append('~'); // indicate digit
            sb.append(c);
            if (count > 1) { // skip output of frequency = 1
                sb.append(count);
            }
            i += count;
        }
        return sb.toString();
    }
    

    测试:

    Stream.of("abc", "aaabccdddd", "1111111111123334553aaa", "111111111112333455~~~aaa")
        .forEach(s -> System.out.printf("%-24s (%2d) -> %s (%d)%n", 
            s, s.length(), compress(s), compress(s).length()
        ));
    

    输出:

    abc                      ( 3) -> abc (3)
    aaabccdddd               (10) -> a3bc2d4 (7)
    1111111111123334553aaa   (22) -> ~111~2~33~4~52~3a3 (18)
    111111111112333455~~~aaa (24) -> ~111~2~33~4~52~~3a3 (19)
    

    【讨论】:

      【解决方案2】:

      问题 1

      alphabet.put(str.charAt(i), 1) 行不断将每个值重置为 1 ,您需要将其放在 else 中

      for (int i = 0; i < str.length(); i++) {
          if (alphabet.containsKey(str.charAt(i))) {
              alphabet.put(str.charAt(i), alphabet.get(str.charAt(i)) + 1);
          } else {
              alphabet.put(str.charAt(i), 1);
          }
      }
      

      问题 2

      第一次修复导致a5b1c5,因为地图有唯一的键,所以你不能计算开头的a和结尾的a


      只需跟踪看到的前一个字符和一个计数器

      public static String compString(String str) {
          StringBuilder sb = new StringBuilder();
          char prev = '\0';
          int count = 0;
          for (char letter : str.toCharArray()) {
              if (prev == '\0') {
                  prev = letter;
              } else if (prev != letter) {
                  sb.append(prev).append(count);
                  count = 0;
                  prev = letter;
              }
              count += 1;
          }
          return sb.append(prev).append(count).toString();
      }
      

      【讨论】:

      • @szechuansauce 你的问题告诉你需要a2blc5a3,而不是a5b1c5。
      • @szechuansauce 这不是你要的^^
      【解决方案3】:
      alphabet.put(str.charAt(i), 1);
      

      不在else语句中,每次都执行

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-03
        • 2016-10-18
        • 2020-08-24
        • 1970-01-01
        • 2011-08-31
        • 1970-01-01
        相关资源
        最近更新 更多