字符串

最小包含子串的长度

image.png
代码:

  1. package org.apache.spark.scala.codeviewguide
  2. import scala.collection.mutable
  3. /**
  4. * 给定字符串str1和str2,求str1的子串中含有str2所有字符的最小子串长度。【举例】
  5. str1="abcde",str2="ac"。因为"abc"包含str2所有的字符,并且在满足这一条件的str1的所有子串中,"abc"是最短的,返回3。
  6. str1="abcdeac", str2="ac". ret=2;
  7. str1="12345",str2="344"。最小包含子串不存在,返回0。
  8. */
  9. object StringMinContainSubStr {
  10. def main(args: Array[String]): Unit = {
  11. val str = "abcdfacddd"
  12. val subStr = "acc"
  13. println(findMinContainSubStr(str, subStr))
  14. }
  15. def findMinContainSubStr(str: String, subStr : String): String = {
  16. val need = subStr.toCharArray
  17. .map((_, 1))
  18. .groupBy(_._1)
  19. .mapValues(_.foldLeft(0)(_ + _._2))
  20. val windows = new mutable.HashMap[Char, Int]()
  21. var valid = 0
  22. var minLen = Integer.MAX_VALUE
  23. var left = 0
  24. var right = 0
  25. var start = 0
  26. while (right < str.length) {
  27. // 扩大窗口找到有效值
  28. val ch = str.charAt(right);
  29. right += 1
  30. if (need.contains(ch)) {
  31. if (windows.contains(ch)) {
  32. windows(ch) += 1
  33. } else {
  34. windows(ch) = 1
  35. }
  36. if (windows(ch) == need(ch)) {
  37. valid += 1 // 有效次+1
  38. }
  39. }
  40. // 缩小窗口。更新可行解
  41. while (valid == need.size) {
  42. if (right - left < minLen) {
  43. start = left
  44. minLen = right - left
  45. }
  46. val ch = str.charAt(left)
  47. left += 1
  48. if (need.contains(ch)) {
  49. // abcdefac and acc. windows去掉第一个a其实并不影响valid值
  50. if (windows(ch) == need(ch)) {
  51. valid -= 1
  52. }
  53. windows(ch) -= 1
  54. }
  55. }
  56. }
  57. str.substring(start, start + minLen)
  58. }
  59. }