Codingbat 挑战:maxBlock

Codingbat challenge: maxBlock

鉴于来自 CodingBat 的任务 maxBlock

给定一个字符串,return字符串中最大“块”的长度。一个块是 运行 个相同的相邻字符。

maxBlock("hoopla") → 2
maxBlock("abbCCCddBBBxx") → 3
maxBlock("") → 0

我的解决方案通过了所有测试,除了一个:

public int maxBlock(String str) {
  int maxBlock = 0;
  int currentBlock = 1;
  
  if (str.length() < 1) {
    return maxBlock;
  } else {
    maxBlock = 1;
  }
  
  for (int i = 0; i < str.length() - 1; i++) {
    if (str.charAt(i) ==  str.charAt(i+1)) {
      currentBlock++;
      if (currentBlock > maxBlock) {
        maxBlock = currentBlock;
        currentBlock = 0;
      }
    }
  }
  
  return maxBlock;
}

这里有什么问题?我该如何解决?

您没有正确重置 currentBlock 计数。如果后面的字符与当前字符不同,则需要将 currentBlock 重置为 1。如果不是,则需要继续增加currentBlock:

public int maxBlock(String str) {
  int maxBlock = 0;
  int currentBlock = 1;
  
  if (str.length() < 1) {
    return maxBlock;
  } else {
    maxBlock = 1;
  }
  
  for (int i = 0; i < str.length() - 1; i++) {
    if (str.charAt(i) ==  str.charAt(i+1)) {
      currentBlock++;
      if (currentBlock > maxBlock) {
        maxBlock = currentBlock;
      }
    } else {
      currentBlock = 1;
    }
  }
  
  return maxBlock;
}

此代码由 GitHub Copilot IntelliJ 插件生成,您只需键入 int maxBlock 然后 GitHub Copilot 生成其余代码:

private int maxBlock(String s) {
    if (s == null || s.length() == 0) return 0;
    int maxBlocks = 0;
    int currentBlocks = 0;
    char currentChar = s.charAt(0);
    for (int i = 0; i < s.length(); i++) {
        if (s.charAt(i) == currentChar) {
            currentBlocks++;
        } else {
            currentBlocks = 1;
            currentChar = s.charAt(i);
        }
        maxBlocks = Math.max(maxBlocks, currentBlocks);
    }
    return maxBlocks;
}

我只在生成的代码中添加了 if (s == null || s.length() == 0) return 0;

虽然我认为@Robby Cornelissen 和@Eskandar Abedini 的解决方案肯定比我的更可行并且更接近原始代码,但我想通过使用正则表达式和一些编码逻辑来提供一种不同的方法。

以下正则表达式查找字符重复出现 0 次或多次的匹配项。这可以与 Matcher class 的 results() 方法一起使用,以提取找到的最长匹配项。

这里有一个link来测试正则表达式

https://regex101.com/r/OcMoQ9/1

代码实现

List<String> testCase = List.of("hoopla", "abbCCCddBBBxx", "", "xyz", "xxyz", "xyzz", "abbbcbbbxbbbx", "XXBBBbbxx", "XXBBBbbxxXXXX", "XX2222BBBbbXX2222");
Pattern pattern = Pattern.compile("(.)(\1*)");
Matcher matcher;

for (String s : testCase) {
    matcher = pattern.matcher(s);
    System.out.printf("%s => %d%n", s, matcher
            .results()
            .map(match -> match.group().length())
            .max(Comparator.comparing(Integer::intValue))
            .orElse(0));
}

//Or even simpliefied like so as @Holger has pointed out in the comments
for (String s : testCase) {
    matcher = pattern.matcher(s);
    System.out.printf("%s => %d%n", s, matcher
            .results()
            .mapToInt(match -> match.group().length())
            .max()
            .orElse(0));
}

Link 测试代码

https://www.jdoodle.com/iembed/v0/rH7

输出

hoopla => 2
abbCCCddBBBxx => 3
 => 0
xyz => 1
xxyz => 2
xyzz => 2
abbbcbbbxbbbx => 3
XXBBBbbxx => 3
XXBBBbbxxXXXX => 4
XX2222BBBbbXX2222 => 4