Java 二进制子字符串的特定长度的每个子字符串应至少有一个“1”字符

Java 二进制子字符串的特定长度的每个子字符串应至少有一个“1”字符,java,arrays,string,algorithm,Java,Arrays,String,Algorithm,您已收到一个仅包含字符“1”和“0”的二进制字符串 计算字符串中需要更改的字符数,以使二进制字符串至少具有某一长度的每个子字符串包含至少一个1字符 我想到了以下想法,但在许多测试案例中都失败了: 公共静态int最小移动字符串s,int d{ int n=s.长度; int i=0,答案=0; 而我只是想抛开一个想法: return s.split("(?<=\\G.{" + String.valueof(d) + "})").stream().fil

您已收到一个仅包含字符“1”和“0”的二进制字符串

计算字符串中需要更改的字符数,以使二进制字符串至少具有某一长度的每个子字符串包含至少一个1字符

我想到了以下想法,但在许多测试案例中都失败了:

公共静态int最小移动字符串s,int d{ int n=s.长度; int i=0,答案=0;
而我只是想抛开一个想法:

return s.split("(?<=\\G.{" + String.valueof(d) + "})").stream().filter(str -> str.contains("1")).count()

我使用滑动窗口技术和Deque解决了这个问题。这是我接受的解决方案:

公共静态int最小移动字符串s,int d{ int n=s.长度; Deque dq=新链接列表; 整数计数=0,答案=0;
forint i=0;i您只需使用滑动窗口,并在每个索引处计算到目前为止的1s。使用d滑动窗口,如果到目前为止没有看到任何索引,则将该窗口的最后一个索引更新为1,并增加结果

代码如下:

public static int minimumMoves(String s, int d) {
    int n = s.length();
    int[] count = new int[n+1];
    int res = 0;
    for ( int i = 1; i <= d; i++ ) {
      if ( s.charAt(i-1) == '1') count[i] = count[i-1]+1;
      else count[i] = count[i-1];
    }
       
    
    if ( count[d] == 0 ) {
      res++;
      count[d] = 1;
    }

    for ( int i = d+1; i <= n; i++ ) {
      if ( s.charAt(i-1) == '0' ) {
        count[i] = count[i-1];
        int ones = count[i] - count[i-d];
        if ( ones == 0 ) {
          count[i] = count[i-1] + 1;
          res++;
        }
        
      } else {
        count[i] = count[i-1] + 1;
      }
      
    }

    return res;
    
  }

您只需要中断,以确保没有运行d零


考虑到另一个实现,您可以从最大可能的更改开始工作,假设开始时所有值都是字符串中的“0”,在找到“1”值时将其减少,然后跳转到下一个子字符串开始。这允许它在上运行,并且Ωn/m n=字符串长度,m=子字符串长度

  public static int minimumMoves(String s, int d)
  {
    char[] a = s.toCharArray();
    
    //Total possible changes (not counting tail)
    if(a.length < d)
      return 0;
    int t = (int) a.length / d;

    //Total possible changes (counting tail)
    //int t = (int) Math.ceil((double) a.length / (double) d);
    
    for(int i = 0; i < a.length; i++)
    {
      if(a[i] == '1')
      {
        t--;
        //Calculate index for start of next substring
        i = (i / d + 1) * d - 1;
      }
    }
    
    return t;
  }

您甚至可以在流上使用parallelStream。您必须这样做!str.contains1,因为您正在计算它需要插入的次数,但在其他方面这与我的想法相同。即使在@TimHunter的建议之后,我也不确定这是否正确。如果s=000000000和d=4,您的代码将生成输出为3。但是正确答案是2,我猜。使用给定正则表达式的String.split方法真的是O | s |吗?除了不清楚的Big-O特征外,Java正则表达式的速度非常慢,特别是当正则表达式仍然需要编译时。@KarthickShiva,这很奇怪。听起来答案检查只是丢弃了字符串尾部的额外子字符串。是否在这里使用窗口技术?这很优雅。假设100010的字符串需要分别分解为100和010,则此代码的输出对于minimumMoves100010,3;@TimHunter它给出minimumMoves100010,3==1。您还期望其他内容吗?我需要在其中添加1以获得例如100110,然后每个长度为3的子字符串都包含是“1”。我想这取决于@KarthickShiva从未给过我们的详细信息。字符串是否必须分解为100和010的清晰子字符串单元,每个子字符串单元至少包含一个1字符,因此不需要调整?或者子字符串分解是否可以应用于字符串中的任何连续字符序列?@TimHunter如前所述它的每个子字符串至少有一定的长度,这对我来说已经足够清楚了。您可以使用任意3个或更多的连续字符。我想这是错误的。如果s=00100和d=2,代码的输出是1。但正确的输出是2。@KarthickShiva您一直在发送关于是否计算字符串尾部的混合注释,即额外的0最后,这不适合整个子字符串长度。这就是为什么我在代码中加入了说明它和不说明它的原因。注释掉不计数尾代码,然后删除说明计数尾的注释。
  public static int minimumMoves(String s, int d)
  {
    char[] a = s.toCharArray();
    
    //Total possible changes (not counting tail)
    if(a.length < d)
      return 0;
    int t = (int) a.length / d;

    //Total possible changes (counting tail)
    //int t = (int) Math.ceil((double) a.length / (double) d);
    
    for(int i = 0; i < a.length; i++)
    {
      if(a[i] == '1')
      {
        t--;
        //Calculate index for start of next substring
        i = (i / d + 1) * d - 1;
      }
    }
    
    return t;
  }