链接的哈希映射计数器未正确递增
Linked Hash Map counter not properly incrementing
试图通过用数字替换重复字符来“压缩”字符串(例如,字符串 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();
}
}
alphabet.put(str.charAt(i), 1);
不在else语句中,每次都执行
问题 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 = '[=11=]';
int count = 0;
for (char letter : str.toCharArray()) {
if (prev == '[=11=]') {
prev = letter;
} else if (prev != letter) {
sb.append(prev).append(count);
count = 0;
prev = letter;
}
count += 1;
}
return sb.append(prev).append(count).toString();
}
如前所述,如果计算所有字符的频率,则需要基于地图的解决方案,但此任务类似于run-length encoding。
值得一提的是,在每个单个字母后添加频率1
似乎是多余的,因为在这种情况下字符串的长度加倍:abc -> a1b1c1
.
此外,如果输入字符串包含其他数字,压缩后的字符串应包含一些“转义”字符以区分数字与计数。
以下代码片段解决了上述问题:
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)
试图通过用数字替换重复字符来“压缩”字符串(例如,字符串 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();
}
}
alphabet.put(str.charAt(i), 1);
不在else语句中,每次都执行
问题 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 = '[=11=]';
int count = 0;
for (char letter : str.toCharArray()) {
if (prev == '[=11=]') {
prev = letter;
} else if (prev != letter) {
sb.append(prev).append(count);
count = 0;
prev = letter;
}
count += 1;
}
return sb.append(prev).append(count).toString();
}
如前所述,如果计算所有字符的频率,则需要基于地图的解决方案,但此任务类似于run-length encoding。
值得一提的是,在每个单个字母后添加频率1
似乎是多余的,因为在这种情况下字符串的长度加倍:abc -> a1b1c1
.
此外,如果输入字符串包含其他数字,压缩后的字符串应包含一些“转义”字符以区分数字与计数。
以下代码片段解决了上述问题:
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)