题目

类型:回溯

image.png

解题思路

搜索+剪枝
数据范围 1<=board.length<=161<=hand.length<=5

为了方便,使用 a 和 b 来代指 boardboard 和 handhand。

但在爆搜过程中同时维持两个字符串构造会超时,考虑使用一个 int 来记录 handhand 的使用情况。

代码

  1. class Solution {
  2. int INF = 0x3f3f3f3f;
  3. String b;
  4. int m;
  5. Map<String, Integer> map = new HashMap<>();
  6. public int findMinStep(String a, String _b) {
  7. b = _b;
  8. m = b.length();
  9. int ans = dfs(a, 1 << m);
  10. return ans == INF ? -1 : ans;
  11. }
  12. int dfs(String a, int cur) {
  13. if (a.length() == 0) return 0;
  14. if (map.containsKey(a)) return map.get(a);
  15. int ans = INF;
  16. int n = a.length();
  17. for (int i = 0; i < m; i++) {
  18. if (((cur >> i) & 1) == 1) continue;
  19. int next = (1 << i) | cur;
  20. for (int j = 0; j <= n; j++) {
  21. boolean ok = false;
  22. if (j > 0 && j < n && a.charAt(j) == a.charAt(j - 1) && a.charAt(j - 1) != b.charAt(i)) ok = true;
  23. if (j < n && a.charAt(j) == b.charAt(i)) ok = true;
  24. if (!ok) continue;
  25. StringBuilder sb = new StringBuilder();
  26. sb.append(a.substring(0, j)).append(b.substring(i, i + 1));
  27. if (j != n) sb.append(a.substring(j));
  28. int k = j;
  29. while (0 <= k && k < sb.length()) {
  30. char c = sb.charAt(k);
  31. int l = k, r = k;
  32. while (l >= 0 && sb.charAt(l) == c) l--;
  33. while (r < sb.length() && sb.charAt(r) == c) r++;
  34. if (r - l - 1 >= 3) {
  35. sb.delete(l + 1, r);
  36. k = l >= 0 ? l : r;
  37. } else {
  38. break;
  39. }
  40. }
  41. ans = Math.min(ans, dfs(sb.toString(), next) + 1);
  42. }
  43. }
  44. map.put(a, ans);
  45. return ans;
  46. }
  47. }