学习内容:

LeeCodeJava并查集

959.由斜杠划分区域(中等)

我的代码

  1. class Solution {
  2. public int regionsBySlashes(String[] grid) {
  3. AndCollect andCollect= new AndCollect();
  4. AndCollect.L=grid.length;
  5. andCollect.resource=new int[AndCollect.L*AndCollect.L*4];
  6. Arrays.fill(andCollect.resource,-1);
  7. int a;
  8. for (int i = 0; i < AndCollect.L; i++) {
  9. int count=-1;
  10. for (int j = 0; j < grid[i].length(); j++) {
  11. count++;
  12. a=AndCollect.getIndex(i,count);
  13. switch (grid[i].charAt(j)){
  14. case ' ':
  15. for (int k = 0; k < 3; k++) {
  16. andCollect.union(a,a+k+1);
  17. }
  18. break;
  19. case '/':
  20. andCollect.union(a,a+3);
  21. andCollect.union(a+1,a+2);
  22. break;
  23. case '\\':
  24. andCollect.union(a,a+1);
  25. andCollect.union(a+2,a+3);
  26. //CharAt()会直接跳过\\中的下一个\
  27. default:
  28. break;
  29. }
  30. if(count!=0){
  31. andCollect.union(a-3,a+3);
  32. }
  33. if(i!=0){
  34. andCollect.union(AndCollect.getIndex(i-1,count)+2,a);
  35. }
  36. }
  37. }
  38. int count=0;
  39. for (int i = 0; i < andCollect.resource.length; i++) {
  40. if(andCollect.resource[i]==-1){
  41. count++;
  42. }
  43. }
  44. return count;
  45. }
  46. static class AndCollect{
  47. int[] resource;
  48. static int L;
  49. public void union(int a, int b){
  50. int fa=find(a);
  51. int fb=find(b);
  52. if(!(fa==fb&&fa!=-1)){
  53. resource[fb]=fa;
  54. }
  55. }
  56. public int find(int a){
  57. while(resource[a]!=-1){
  58. a=resource[a];
  59. }
  60. return a;
  61. }
  62. /**@apiNote 获取目标方格的第一个三角*/
  63. static int getIndex(int lin,int cul){
  64. return (lin*L+cul)*4;
  65. //这里注意是每个格子占了四个位置.
  66. }
  67. }
  68. }

思路:

通过将一个格子根据对角线分成四个三角形,将每个格子的四个三角形展开,化成一个一维数组,构成并查集,之后根据划线的状态,分别将对应的位置的集合进行划分操作,最后判断根节点一共有几个.

注意点:

1.在Java中’\‘视作一个字符,即’\’,在chatAt()中不需要另外操作.
2.应该注意,灵魂之处在于小三角的展开,这是将二维数组一维化形成并查集的关键.
3.不光需要格子内部的三角形之间的联系,也需要格子之间的联系,因为分隔是在格子之间分割的,所以相邻三角形之间可以无脑链接.

改进处

1.使用-1作为根节点的判定具有局限性,标准的并查集应当使用其本身的index作为值,以判断其是否为根节点.
2.尝试在find()处使用递归函数.

改进代码

  1. class Solution {
  2. public int regionsBySlashes(String[] grid) {
  3. AndCollect andCollect= new AndCollect();
  4. AndCollect.L=grid.length;
  5. andCollect.resource=new int[AndCollect.L*AndCollect.L*4];
  6. for (int i = 0; i < andCollect.resource.length; i++) {
  7. andCollect.resource[i]=i;
  8. }
  9. int a;
  10. for (int i = 0; i < AndCollect.L; i++) {
  11. int count=-1;
  12. for (int j = 0; j < grid[i].length(); j++) {
  13. count++;
  14. a=AndCollect.getIndex(i,count);
  15. switch (grid[i].charAt(j)){
  16. case ' ':
  17. for (int k = 0; k < 3; k++) {
  18. andCollect.union(a,a+k+1);
  19. }
  20. break;
  21. case '/':
  22. andCollect.union(a,a+3);
  23. andCollect.union(a+1,a+2);
  24. break;
  25. case '\\':
  26. andCollect.union(a,a+1);
  27. andCollect.union(a+2,a+3);
  28. //CharAt()会直接跳过\\中的下一个\
  29. default:
  30. break;
  31. }
  32. if(count!=0){
  33. andCollect.union(a-3,a+3);
  34. }
  35. if(i!=0){
  36. andCollect.union(AndCollect.getIndex(i-1,count)+2,a);
  37. }
  38. }
  39. }
  40. int count=0;
  41. for (int i = 0; i < andCollect.resource.length; i++) {
  42. if(andCollect.resource[i]==i){
  43. count++;
  44. }
  45. }
  46. return count;
  47. }
  48. static class AndCollect{
  49. int[] resource;
  50. static int L;
  51. public void union(int a, int b){
  52. int fa=find(a);
  53. int fb=find(b);
  54. if(fa!=fb){
  55. resource[fb]=fa;
  56. }
  57. }
  58. public int find(int a){
  59. if(resource[a]==a){
  60. return a;
  61. }else{
  62. return find(resource[a]);
  63. }
  64. }
  65. /**@apiNote 获取目标方格的第一个三角*/
  66. static int getIndex(int lin,int cul){
  67. return (lin*L+cul)*4;
  68. //这里注意是每个格子占了四个位置.
  69. }
  70. }
  71. }

结果

减少了一点内存,将根节点改为其本身的index,相对来说可以减少逻辑的复杂程度,同时也可以让find()方法使用递归的方法,而不用担心内部死循环是一个值得记住的好习惯.

优解代码

  1. class Solution {
  2. public int regionsBySlashes(String[] grid) {
  3. final int len = grid.length + 1;
  4. final DSU dus = new DSU(len * len);
  5. int t1 = len * (len - 1);
  6. //这个是让全图都与0相连接,或者说都与第一个连接
  7. for (int i = 0; i < len; i++) {
  8. dus.union(0, i);
  9. dus.union(0, i * len);
  10. dus.union(0, i + t1);
  11. dus.union(0, (i + 1) * len - 1);
  12. }
  13. int result = 1;
  14. for (int i = 0; i < len - 1; i++) {
  15. for (int j = 0; j < len - 1; j++) {
  16. char c = grid[i].charAt(j);
  17. int index = i * len + j + 1;
  18. if (c == '\\') {
  19. if (dus.union(index - 1, index + len)) result++;
  20. } else if (c == '/') {
  21. if (dus.union(index, index + len - 1)) result++;
  22. }
  23. }
  24. }
  25. return result;
  26. }
  27. class DSU {
  28. int[] temps;
  29. public DSU(int n) {
  30. temps = new int[n];
  31. for (int i = 0; i < n; i++) {
  32. temps[i] = i;
  33. }
  34. }
  35. public int find(int n) {
  36. if (temps[n] == n) return n;
  37. temps[n] = find(temps[n]);
  38. return temps[n];
  39. }
  40. public boolean union(int x, int y) {
  41. int tx = find(x);
  42. int ty = find(y);
  43. if (tx == ty) return true;
  44. temps[ty] = tx;
  45. return false;
  46. }
  47. }

结论:

看不懂QAQ