0
点赞
收藏
分享

微信扫一扫

从零学算法1542

阎小妍 2024-05-26 阅读 10
  • 首先一个不难发现的规律,要能够组成回文串,那不同的字符最多只能有一个,相当于一个字符串中 0~9 每个字符串的个数只能有一个为奇数个,其余都应该为偶数个。由于只有 0~9 这 10 种字符,那么我们可以用一个 10 位二进制数 status 来表示一个字符串的每个字符的奇偶性,0 表示有偶数个,1 表示有奇数个。例如 123 对应的 status 为 0000001110,而 1123 就对应 0000001100。
  • 最核心也是最难理解的一点就是,为什么我们可以通过两个 status 来确定是否存在一个超赞子字符串。
  • 我们将 00,1122,006677 这种形式称为字符对。
  • 假设 t[i] 为 s[0,i] 对应的 status, 如果有 t[i] 和 t[j] 只相差最多一位的奇偶性,那么 s[i,j] 就是超赞子字符串,因为他们相差的的部分是大于等于 0 个字符对,以及 1 个某个字符,这不就符合我们发现的规律吗。例如 123 和 12300,因为他们只相差了偶数个 0,或者 123 和 123001122,相差了偶数个 0、1、2,所以他们的 status 相同,他们之间相差的 00 或是 001122 就超赞的,或者比如 123 和 123001,他们的 status 只相差一位,那么 001 也超赞的。
  • 我们从左到右遍历 s,用一个数组 pre 存储第一次出现某个 status 时的下标,如果之后又出现了相同的 status 那么就相当于出现了相同的 status,得到了一次超赞子字符串;或者我们每次遍历时,尝试对 status 的某一位取反得到 t[j],如果真的有这样的 t[j] 就说明可以得到这样的只相差一位的 status,那也计算一次
  • 剩下的就是具体实现的细节了,由于 pre 数组存储 status 第一次出现的下标,所以需要初始化成小于 0 的数防止被当成下标,又因为理论上来说空字符串所对应的 status 也是 0,因为空字符串相当于每个字符都是 0 个,即都是偶数个,那自然为 0,所以第一次出现 status 为 0 的下标是 -1,所以我们就初始化 pre[0] 为 -1,其他的可以初始化比如 -2 或者其他负数。
  • 剩下的状态压缩,按位取反就是简单的位运算了
  •   public int longestAwesome(String s) { 
          int status = 0, res = 0;
          int[] pre = new int[1 << 10];
          Arrays.fill(pre, -2);
          pre[0] = -1;
          for(int i = 0; i < s.length(); i++){
              status ^= 1 << (s.charAt(i) - '0');
              // status 相差 0 位时需要比较一次长度
              if(pre[status] != -2)res = Math.max(res, i - pre[status]);
              else pre[status] = i;
              // 看有没有和当前 status 只相差 1 位的 status2
              for(int j = 0; j < 10; j++){
                  int status2 = status ^ (1 << j);
                  if(pre[status2] != -2)res = Math.max(res, i - pre[status2]);
              }
          }
          return res;
      }
    
举报

相关推荐

0 条评论