给定一个仅由 0 和 1 组成的二进制字符串S。计算这个字符串的子串数,使得子串的长度可以被子串中 1 的个数整除。
例子:
Input: S = “01010”
Output: 10
Input: S = “1111100000”
Output: 25
天真的方法:
- 遍历所有子串,并为每个子串计算 1 的数量。如果子串的长度可以被 1 的计数整除,则增加计数。这种方法将花费 O(N 3 ) 时间。
- 为了使解决方案更有效,我们可以使用 Prefix Sum Array,而不是遍历整个子字符串来计算其中 1 的数量。
number of 1’s in the substring [l: r] = prefix_sum[r] – prefix_sum[l – 1]
下面是上述方法的实现。
C++
// C++ program to count number of
// substring under given condition
#include
using namespace std;
// Function return count of
// such substring
int countOfSubstrings(string s)
{
int n = s.length();
int prefix_sum[n] = { 0 };
// Mark 1 at those indices
// where '1' appears
for (int i = 0; i < n; i++) {
if (s[i] == '1')
prefix_sum[i] = 1;
}
// Take prefix sum
for (int i = 1; i < n; i++)
prefix_sum[i] += prefix_sum[i - 1];
int answer = 0;
// Iterate through all the
// substrings
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
int countOfOnes = prefix_sum[j]
- (i - 1 >= 0 ?
prefix_sum[i - 1] : 0);
int length = j - i + 1;
if (countOfOnes > 0 &&
length % countOfOnes == 0)
answer++;
}
}
return answer;
}
// Driver Code
int main()
{
string S = "1111100000";
cout << countOfSubstrings(S);
return 0;
}
Java
// Java program to count number of
// subString under given condition
import java.util.*;
class GFG{
// Function return count of
// such substring
static int countOfSubStrings(String s)
{
int n = s.length();
int []prefix_sum = new int[n];
// Mark 1 at those indices
// where '1' appears
for (int i = 0; i < n; i++) {
if (s.charAt(i) == '1')
prefix_sum[i] = 1;
}
// Take prefix sum
for (int i = 1; i < n; i++)
prefix_sum[i] += prefix_sum[i - 1];
int answer = 0;
// Iterate through all the
// subStrings
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
int countOfOnes = prefix_sum[j]
- (i - 1 >= 0 ?
prefix_sum[i - 1] : 0);
int length = j - i + 1;
if (countOfOnes > 0 &&
length % countOfOnes == 0)
answer++;
}
}
return answer;
}
// Driver Code
public static void main(String[] args)
{
String S = "1111100000";
System.out.print(countOfSubStrings(S));
}
}
// This code contributed by sapnasingh4991
Python3
# Python3 program to count number of
# substring under given condition
# Function return count of
# such substring
def countOfSubstrings(s):
n = len(s)
prefix_sum = [0 for i in range(n)]
# Mark 1 at those indices
# where '1' appears
for i in range(n):
if (s[i] == '1'):
prefix_sum[i] = 1
# Take prefix sum
for i in range(1, n, 1):
prefix_sum[i] += prefix_sum[i - 1]
answer = 0
# Iterate through all the
# substrings
for i in range(n):
for j in range(i, n, 1):
if (i - 1 >= 0):
countOfOnes = prefix_sum[j]- prefix_sum[i - 1]
else:
countOfOnes = prefix_sum[j]
length = j - i + 1
if (countOfOnes > 0 and length % countOfOnes == 0):
answer += 1
return answer
# Driver Code
if __name__ == '__main__':
S = "1111100000"
print(countOfSubstrings(S))
# This code is contributed by Bhupendra_Singh
C#
// C# program to count number of
// subString under given condition
using System;
class GFG{
// Function return count of
// such substring
static int countOfSubStrings(String s)
{
int n = s.Length;
int []prefix_sum = new int[n];
// Mark 1 at those indices
// where '1' appears
for(int i = 0; i < n; i++)
{
if (s[i] == '1')
prefix_sum[i] = 1;
}
// Take prefix sum
for(int i = 1; i < n; i++)
prefix_sum[i] += prefix_sum[i - 1];
int answer = 0;
// Iterate through all the
// subStrings
for(int i = 0; i < n; i++)
{
for(int j = i; j < n; j++)
{
int countOfOnes = prefix_sum[j] -
(i - 1 >= 0 ?
prefix_sum[i - 1] : 0);
int length = j - i + 1;
if (countOfOnes > 0 &&
length % countOfOnes == 0)
answer++;
}
}
return answer;
}
// Driver Code
public static void Main(String[] args)
{
String S = "1111100000";
Console.Write(countOfSubStrings(S));
}
}
// This code is contributed by Rohit_ranjan
Javascript
C++
// C++ program to count number of
// substring under given condition
#include
using namespace std;
// Function return count of such
// substring
int countOfSubstrings(string s)
{
int n = s.length();
// Selection of adequate x value
int x = sqrt(n);
// Store where 1's are located
vector ones;
for (int i = 0; i < n; i++) {
if (s[i] == '1')
ones.push_back(i);
}
// If there are no ones,
// then answer is 0
if (ones.size() == 0)
return 0;
// For ease of implementation
ones.push_back(n);
// Count storage
vector totCount(n * x + n);
int sum = 0;
// Iterate on all k values less
// than fixed x
for (int k = 0; k <= x; k++) {
// Keeps a count of 1's occured
// during string traversal
int now = 0;
totCount[k * n]++;
// Iterate on string and modify
// the totCount
for (int j = 1; j <= n; j++) {
// If this character is 1
if (s[j - 1] == '1')
now++;
int index = j - k * now;
// Add to the final sum/count
sum += totCount[index + k * n];
// Increase totCount at exterior
// position
totCount[index + k * n]++;
}
now = 0;
totCount[k * n]--;
for (int j = 1; j <= n; j++) {
if (s[j - 1] == '1')
now++;
int index = j - k * now;
// Reduce totCount at index + k*n
totCount[index + k * n]--;
}
}
// Slightly modified prefix sum storage
int prefix_sum[n];
memset(prefix_sum, -1, sizeof(prefix_sum));
// Number of 1's till i-1
int cnt = 0;
for (int i = 0; i < n; i++) {
prefix_sum[i] = cnt;
if (s[i] == '1')
cnt++;
}
// Traversing over string considering
// each position and finding bounds
// and count using the inequalities
for (int k = 0; k < n; k++)
{
for (int j = 1; j <= (n / x)
&& prefix_sum[k] + j <= cnt; j++)
{
// Calculating bounds for l and r
int l = ones[prefix_sum[k] + j - 1]
- k + 1;
int r = ones[prefix_sum[k] + j] - k;
l = max(l, j * (x + 1));
// If valid then add to answer
if (l <= r) {
sum += r / j - (l - 1) / j;
}
}
}
return sum;
}
int main()
{
string S = "1111100000";
cout << countOfSubstrings(S);
return 0;
}
Java
// Java program to count number of
// subString under given condition
import java.util.*;
class GFG{
// Function return count of such
// substring
static int countOfSubStrings(String s)
{
int n = s.length();
// Selection of adequate x value
int x = (int)Math.sqrt(n);
// Store where 1's are located
Vector ones = new Vector();
for(int i = 0; i < n; i++)
{
if (s.charAt(i) == '1')
ones.add(i);
}
// If there are no ones,
// then answer is 0
if (ones.size() == 0)
return 0;
// For ease of implementation
ones.add(n);
// Count storage
int []totCount = new int[n * x + n];
int sum = 0;
// Iterate on all k values less
// than fixed x
for(int k = 0; k <= x; k++)
{
// Keeps a count of 1's occured
// during String traversal
int now = 0;
totCount[k * n]++;
// Iterate on String and modify
// the totCount
for(int j = 1; j <= n; j++)
{
// If this character is 1
if (s.charAt(j - 1) == '1')
now++;
int index = j - k * now;
// Add to the final sum/count
sum += totCount[index + k * n];
// Increase totCount at exterior
// position
totCount[index + k * n]++;
}
now = 0;
totCount[k * n]--;
for(int j = 1; j <= n; j++)
{
if (s.charAt(j - 1) == '1')
now++;
int index = j - k * now;
// Reduce totCount at index + k*n
totCount[index + k * n]--;
}
}
// Slightly modified prefix sum storage
int []prefix_sum = new int[n];
Arrays.fill(prefix_sum, -1);
// Number of 1's till i-1
int cnt = 0;
for(int i = 0; i < n; i++)
{
prefix_sum[i] = cnt;
if (s.charAt(i) == '1')
cnt++;
}
// Traversing over String considering
// each position and finding bounds
// and count using the inequalities
for(int k = 0; k < n; k++)
{
for(int j = 1; j <= (n / x) &&
prefix_sum[k] + j <= cnt; j++)
{
// Calculating bounds for l and r
int l = ones.get(prefix_sum[k] + j - 1)-
k + 1;
int r = ones.get(prefix_sum[k] + j) - k;
l = Math.max(l, j * (x + 1));
// If valid then add to answer
if (l <= r)
{
sum += r / j - (l - 1) / j;
}
}
}
return sum;
}
// Driver code
public static void main(String[] args)
{
String S = "1111100000";
System.out.print(countOfSubStrings(S));
}
}
// This code is contributed by Amit Katiyar
Python3
# Python3 program to count number of
# substring under given condition
import math
# Function return count of such
# substring
def countOfSubstrings(s):
n = len(s)
# Selection of adequate x value
x = int(math.sqrt(n))
# Store where 1's are located
ones = []
for i in range (n):
if (s[i] == '1'):
ones.append(i)
# If there are no ones,
# then answer is 0
if (len(ones) == 0):
return 0
# For ease of implementation
ones.append(n)
# Count storage
totCount = [0] * (n * x + n)
sum = 0
# Iterate on all k values less
# than fixed x
for k in range(x + 1):
# Keeps a count of 1's occured
# during string traversal
now = 0
totCount[k * n] += 1
# Iterate on string and modify
# the totCount
for j in range(1, n + 1):
# If this character is 1
if (s[j - 1] == '1'):
now += 1
index = j - k * now
# Add to the final sum/count
sum += totCount[index + k * n]
# Increase totCount at exterior
# position
totCount[index + k * n] += 1
now = 0
totCount[k * n] -= 1
for j in range(1, n + 1):
if (s[j - 1] == '1'):
now += 1
index = j - k * now
# Reduce totCount at index + k*n
totCount[index + k * n] -= 1
# Slightly modified prefix sum storage
prefix_sum = [-1] * n
# Number of 1's till i-1
cnt = 0
for i in range(n):
prefix_sum[i] = cnt
if (s[i] == '1'):
cnt += 1
# Traversing over string considering
# each position and finding bounds
# and count using the inequalities
for k in range(n):
j = 1
while (j <= (n // x) and
prefix_sum[k] + j <= cnt):
# Calculating bounds for l and r
l = (ones[prefix_sum[k] + j - 1] -
k + 1)
r = ones[prefix_sum[k] + j] - k
l = max(l, j * (x + 1))
# If valid then add to answer
if (l <= r):
sum += r // j - (l - 1) // j
j += 1
return sum
# Driver code
if __name__ == "__main__":
S = "1111100000"
print (countOfSubstrings(S))
# This code is contributed by chitranayal
C#
// C# program to count number of
// subString under given condition
using System;
using System.Collections.Generic;
class GFG{
// Function return count of such
// substring
static int countOfSubStrings(String s)
{
int n = s.Length;
// Selection of adequate x value
int x = (int)Math.Sqrt(n);
// Store where 1's are located
List ones = new List();
for(int i = 0; i < n; i++)
{
if (s[i] == '1')
ones.Add(i);
}
// If there are no ones,
// then answer is 0
if (ones.Count == 0)
return 0;
// For ease of implementation
ones.Add(n);
// Count storage
int []totCount = new int[n * x + n];
int sum = 0;
// Iterate on all k values less
// than fixed x
for(int k = 0; k <= x; k++)
{
// Keeps a count of 1's occured
// during String traversal
int now = 0;
totCount[k * n]++;
// Iterate on String and modify
// the totCount
for(int j = 1; j <= n; j++)
{
// If this character is 1
if (s[j-1] == '1')
now++;
int index = j - k * now;
// Add to the readonly sum/count
sum += totCount[index + k * n];
// Increase totCount at exterior
// position
totCount[index + k * n]++;
}
now = 0;
totCount[k * n]--;
for(int j = 1; j <= n; j++)
{
if (s[j-1] == '1')
now++;
int index = j - k * now;
// Reduce totCount at index + k*n
totCount[index + k * n]--;
}
}
// Slightly modified prefix sum storage
int []prefix_sum = new int[n];
for(int i = 0; i < n; i++)
prefix_sum [i]= -1;
// Number of 1's till i-1
int cnt = 0;
for(int i = 0; i < n; i++)
{
prefix_sum[i] = cnt;
if (s[i] == '1')
cnt++;
}
// Traversing over String considering
// each position and finding bounds
// and count using the inequalities
for(int k = 0; k < n; k++)
{
for(int j = 1; j <= (n / x) &&
prefix_sum[k] + j <= cnt; j++)
{
// Calculating bounds for l and r
int l = ones[prefix_sum[k] + j - 1]-
k + 1;
int r = ones[prefix_sum[k] + j] - k;
l = Math.Max(l, j * (x + 1));
// If valid then add to answer
if (l <= r)
{
sum += r / j - (l - 1) / j;
}
}
}
return sum;
}
// Driver code
public static void Main(String[] args)
{
String S = "1111100000";
Console.Write(countOfSubStrings(S));
}
}
// This code is contributed by Amit Katiyar
Javascript
输出:
25
时间复杂度: O(N 2 )
有效的方法:
- 让我们使用前面方法中讨论的前缀和数组。让我们取一个遵循给定条件的子串 [l: r] ,我们可以说:
r – l + 1 = k * (prefix_sum[r] – prefix_sum[l-1]), where k is some integer
- 这也可以写成:
r – k * prefix_sum[r] = l – 1 – k * prefix_sum[l-1]
观察这个方程,我们可以创建另一个数组 B[i] = i – k * prefix_sum[i],对于 0 <= k < n。所以,现在的问题是计算 B 中每个 k 的相等整数对的数量。
- 让我们取一个固定的数字 x。如果 k > x,那么当 r – l + 1 <= n (对于任何一对 l, r ),我们得到以下不等式:
prefix_sum[r] – prefix_sum[l-1] = (r – l + 1)/k <= n/x
- 这继续表明满足给定条件的子串中的 1 和 k 的数量并不大。 (这只是为了估计效率)。现在对于 k <= x,我们需要计算相等整数对的数量。这里满足以下不等式:
(-1) *n*x <= i – k – prefix_sum[i] <= n
- 因此,我们可以将每个 k 的所有数字独立地放入一个数组中,并找到相等整数的个数。
- 下一步是修复 l 的值并迭代字符串中 1 的数量,并为每个值获取 r 的边界。对于给定的 1 数量,我们可以评估哪个余数将给出 r。现在的问题是计算某些段上的整数数,当除以某个固定整数时,它会给出一些固定余数 (rem)。这个计算可以在 O(1) 中完成。另外,请注意,仅计算 k > x 的 r 值很重要。
下面是上述方法的实现。
C++
// C++ program to count number of
// substring under given condition
#include
using namespace std;
// Function return count of such
// substring
int countOfSubstrings(string s)
{
int n = s.length();
// Selection of adequate x value
int x = sqrt(n);
// Store where 1's are located
vector ones;
for (int i = 0; i < n; i++) {
if (s[i] == '1')
ones.push_back(i);
}
// If there are no ones,
// then answer is 0
if (ones.size() == 0)
return 0;
// For ease of implementation
ones.push_back(n);
// Count storage
vector totCount(n * x + n);
int sum = 0;
// Iterate on all k values less
// than fixed x
for (int k = 0; k <= x; k++) {
// Keeps a count of 1's occured
// during string traversal
int now = 0;
totCount[k * n]++;
// Iterate on string and modify
// the totCount
for (int j = 1; j <= n; j++) {
// If this character is 1
if (s[j - 1] == '1')
now++;
int index = j - k * now;
// Add to the final sum/count
sum += totCount[index + k * n];
// Increase totCount at exterior
// position
totCount[index + k * n]++;
}
now = 0;
totCount[k * n]--;
for (int j = 1; j <= n; j++) {
if (s[j - 1] == '1')
now++;
int index = j - k * now;
// Reduce totCount at index + k*n
totCount[index + k * n]--;
}
}
// Slightly modified prefix sum storage
int prefix_sum[n];
memset(prefix_sum, -1, sizeof(prefix_sum));
// Number of 1's till i-1
int cnt = 0;
for (int i = 0; i < n; i++) {
prefix_sum[i] = cnt;
if (s[i] == '1')
cnt++;
}
// Traversing over string considering
// each position and finding bounds
// and count using the inequalities
for (int k = 0; k < n; k++)
{
for (int j = 1; j <= (n / x)
&& prefix_sum[k] + j <= cnt; j++)
{
// Calculating bounds for l and r
int l = ones[prefix_sum[k] + j - 1]
- k + 1;
int r = ones[prefix_sum[k] + j] - k;
l = max(l, j * (x + 1));
// If valid then add to answer
if (l <= r) {
sum += r / j - (l - 1) / j;
}
}
}
return sum;
}
int main()
{
string S = "1111100000";
cout << countOfSubstrings(S);
return 0;
}
Java
// Java program to count number of
// subString under given condition
import java.util.*;
class GFG{
// Function return count of such
// substring
static int countOfSubStrings(String s)
{
int n = s.length();
// Selection of adequate x value
int x = (int)Math.sqrt(n);
// Store where 1's are located
Vector ones = new Vector();
for(int i = 0; i < n; i++)
{
if (s.charAt(i) == '1')
ones.add(i);
}
// If there are no ones,
// then answer is 0
if (ones.size() == 0)
return 0;
// For ease of implementation
ones.add(n);
// Count storage
int []totCount = new int[n * x + n];
int sum = 0;
// Iterate on all k values less
// than fixed x
for(int k = 0; k <= x; k++)
{
// Keeps a count of 1's occured
// during String traversal
int now = 0;
totCount[k * n]++;
// Iterate on String and modify
// the totCount
for(int j = 1; j <= n; j++)
{
// If this character is 1
if (s.charAt(j - 1) == '1')
now++;
int index = j - k * now;
// Add to the final sum/count
sum += totCount[index + k * n];
// Increase totCount at exterior
// position
totCount[index + k * n]++;
}
now = 0;
totCount[k * n]--;
for(int j = 1; j <= n; j++)
{
if (s.charAt(j - 1) == '1')
now++;
int index = j - k * now;
// Reduce totCount at index + k*n
totCount[index + k * n]--;
}
}
// Slightly modified prefix sum storage
int []prefix_sum = new int[n];
Arrays.fill(prefix_sum, -1);
// Number of 1's till i-1
int cnt = 0;
for(int i = 0; i < n; i++)
{
prefix_sum[i] = cnt;
if (s.charAt(i) == '1')
cnt++;
}
// Traversing over String considering
// each position and finding bounds
// and count using the inequalities
for(int k = 0; k < n; k++)
{
for(int j = 1; j <= (n / x) &&
prefix_sum[k] + j <= cnt; j++)
{
// Calculating bounds for l and r
int l = ones.get(prefix_sum[k] + j - 1)-
k + 1;
int r = ones.get(prefix_sum[k] + j) - k;
l = Math.max(l, j * (x + 1));
// If valid then add to answer
if (l <= r)
{
sum += r / j - (l - 1) / j;
}
}
}
return sum;
}
// Driver code
public static void main(String[] args)
{
String S = "1111100000";
System.out.print(countOfSubStrings(S));
}
}
// This code is contributed by Amit Katiyar
蟒蛇3
# Python3 program to count number of
# substring under given condition
import math
# Function return count of such
# substring
def countOfSubstrings(s):
n = len(s)
# Selection of adequate x value
x = int(math.sqrt(n))
# Store where 1's are located
ones = []
for i in range (n):
if (s[i] == '1'):
ones.append(i)
# If there are no ones,
# then answer is 0
if (len(ones) == 0):
return 0
# For ease of implementation
ones.append(n)
# Count storage
totCount = [0] * (n * x + n)
sum = 0
# Iterate on all k values less
# than fixed x
for k in range(x + 1):
# Keeps a count of 1's occured
# during string traversal
now = 0
totCount[k * n] += 1
# Iterate on string and modify
# the totCount
for j in range(1, n + 1):
# If this character is 1
if (s[j - 1] == '1'):
now += 1
index = j - k * now
# Add to the final sum/count
sum += totCount[index + k * n]
# Increase totCount at exterior
# position
totCount[index + k * n] += 1
now = 0
totCount[k * n] -= 1
for j in range(1, n + 1):
if (s[j - 1] == '1'):
now += 1
index = j - k * now
# Reduce totCount at index + k*n
totCount[index + k * n] -= 1
# Slightly modified prefix sum storage
prefix_sum = [-1] * n
# Number of 1's till i-1
cnt = 0
for i in range(n):
prefix_sum[i] = cnt
if (s[i] == '1'):
cnt += 1
# Traversing over string considering
# each position and finding bounds
# and count using the inequalities
for k in range(n):
j = 1
while (j <= (n // x) and
prefix_sum[k] + j <= cnt):
# Calculating bounds for l and r
l = (ones[prefix_sum[k] + j - 1] -
k + 1)
r = ones[prefix_sum[k] + j] - k
l = max(l, j * (x + 1))
# If valid then add to answer
if (l <= r):
sum += r // j - (l - 1) // j
j += 1
return sum
# Driver code
if __name__ == "__main__":
S = "1111100000"
print (countOfSubstrings(S))
# This code is contributed by chitranayal
C#
// C# program to count number of
// subString under given condition
using System;
using System.Collections.Generic;
class GFG{
// Function return count of such
// substring
static int countOfSubStrings(String s)
{
int n = s.Length;
// Selection of adequate x value
int x = (int)Math.Sqrt(n);
// Store where 1's are located
List ones = new List();
for(int i = 0; i < n; i++)
{
if (s[i] == '1')
ones.Add(i);
}
// If there are no ones,
// then answer is 0
if (ones.Count == 0)
return 0;
// For ease of implementation
ones.Add(n);
// Count storage
int []totCount = new int[n * x + n];
int sum = 0;
// Iterate on all k values less
// than fixed x
for(int k = 0; k <= x; k++)
{
// Keeps a count of 1's occured
// during String traversal
int now = 0;
totCount[k * n]++;
// Iterate on String and modify
// the totCount
for(int j = 1; j <= n; j++)
{
// If this character is 1
if (s[j-1] == '1')
now++;
int index = j - k * now;
// Add to the readonly sum/count
sum += totCount[index + k * n];
// Increase totCount at exterior
// position
totCount[index + k * n]++;
}
now = 0;
totCount[k * n]--;
for(int j = 1; j <= n; j++)
{
if (s[j-1] == '1')
now++;
int index = j - k * now;
// Reduce totCount at index + k*n
totCount[index + k * n]--;
}
}
// Slightly modified prefix sum storage
int []prefix_sum = new int[n];
for(int i = 0; i < n; i++)
prefix_sum [i]= -1;
// Number of 1's till i-1
int cnt = 0;
for(int i = 0; i < n; i++)
{
prefix_sum[i] = cnt;
if (s[i] == '1')
cnt++;
}
// Traversing over String considering
// each position and finding bounds
// and count using the inequalities
for(int k = 0; k < n; k++)
{
for(int j = 1; j <= (n / x) &&
prefix_sum[k] + j <= cnt; j++)
{
// Calculating bounds for l and r
int l = ones[prefix_sum[k] + j - 1]-
k + 1;
int r = ones[prefix_sum[k] + j] - k;
l = Math.Max(l, j * (x + 1));
// If valid then add to answer
if (l <= r)
{
sum += r / j - (l - 1) / j;
}
}
}
return sum;
}
// Driver code
public static void Main(String[] args)
{
String S = "1111100000";
Console.Write(countOfSubStrings(S));
}
}
// This code is contributed by Amit Katiyar
Javascript
输出:
25
时间复杂度:
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。