二进制字符串中三元组的计数,使得 S[i]、S[j] 和 S[j]、S[k] 的按位与相同
给定一个长度为N的二进制字符串S ,由 0 和 1 组成。任务是计算三元组(i, j, k)的数量,使得S[i] & S[j] = S[j] & S[k] ,其中0 ≤ i < j < k < N和&表示按位与运算符。
例子:
Input: N = 4, S = “0010”
Output: 4
Explanation: Following are 4 triplets which satisfy the condition S[i] & S[j] = S[j] & S[k]
(0, 1, 2) because 0 & 0 = 0 & 1,
(0, 1, 3) because 0 & 0 = 0 & 0,
(0, 2, 3) because 0 & 1 = 1 & 0,
(1, 2, 3) because 0 & 1 = 1 & 0.
Input: N = 5, S = “00101”
Output: 8
Explanation: 8 triplets satisfying the above condition are :
(0, 1, 2) because 0 & 0 = 0 & 1.
(0, 1, 3) because 0 & 0 = 0 & 0.
(0, 1, 4) because 0 & 0 = 0 & 1.
(0, 2, 3) because 0 & 1 = 1 & 0.
(1, 2, 3) because 0 & 1 = 1 & 0.
(0, 3, 4) because 0 & 0 = 0 & 1.
(1, 3, 4) because 0 & 0 = 0 & 1.
(2, 3, 4) because 1 & 0 = 0 & 1.
天真的方法:解决问题的最简单方法是:
Generate all possible triplets and check if S[i] & S[j] = S[j] & S[k].
请按照以下步骤解决此问题:
- 声明一个变量ans并将其初始化为0以存储总计数。
- 现在,需要三个嵌套循环来遍历所有三元组。
- 第一个循环遍历索引i ,第二个遍历索引j从i+1开始,第三个遍历索引k从j+1开始。
- 现在,检查条件S[i] & S[j] = S[j] & S[k]是否为真。如果为真,则将ans增加1 。
- 返回三元组的总数。
以下是上述方法的实现:
C++
// C++ program for above approach
#include
using namespace std;
// Function to count total number of triplets
int countTriplets(int n, string& s)
{
// Stores the count of triplets.
int ans = 0;
// Iterate over all the triplets.
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
for (int k = j + 1; k < n; ++k) {
// Extract integer from 'S[i]',
// 'S[j]', 'S[k]'.
int x = s[i] - '0';
int y = s[j] - '0',
z = s[k] - '0';
// If condition 'S[i]' & 'S[j]'
// == 'S[j]' &'S[k]' is true,
// increment 'ans'.
if ((x & y) == (y & z)) {
ans++;
}
}
}
}
// Return the answer
return ans;
}
// Driver code
int main()
{
int N = 4;
string S = "0010";
// Function call
cout << countTriplets(N, S);
return 0;
}
Java
// JAVA program for above approach
import java.util.*;
class GFG {
// Function to count total number of triplets
public static int countTriplets(int n, String s)
{
// Stores the count of triplets.
int ans = 0;
// Iterate over all the triplets.
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
for (int k = j + 1; k < n; ++k) {
// Extract integer from 'S[i]',
// 'S[j]', 'S[k]'.
int x = s.charAt(i);
int y = s.charAt(j), z = s.charAt(k);
// If condition 'S[i]' & 'S[j]'
// == 'S[j]' &'S[k]' is true,
// increment 'ans'.
if ((x & y) == (y & z)) {
ans++;
}
}
}
}
// Return the answer
return ans;
}
// Driver code
public static void main(String[] args)
{
int N = 4;
String S = "0010";
// Function call
System.out.print(countTriplets(N, S));
}
}
// This code is contributed by Taranpreet
Python3
# Python3 program for above approach
# Function to count total number of triplets
def countTriplets(n, s):
# Stores the count of triplets.
ans = 0
# Iterate over all the triplets.
for i in range(n):
for j in range(i + 1, n):
for k in range(j + 1, n):
# Extract integer from 'S[i]', S[j], S[k]
x = ord(S[i]) - ord("0")
y = ord(S[j]) - ord("0")
z = ord(S[k]) - ord("0")
# If condition 'S[i]' & 'S[j]'
# == S[j]' & 'S[k]'
# is true, increment ans
if (x & y) == (y & z):
ans += 1
# return the answer
return ans
# Driver code
N = 4
S = "0010"
# function call
print(countTriplets(N, S))
# This code is contributed by hrithikgarg03188.
C#
// C# program for above approach
using System;
public class GFG{
// Function to count total number of triplets
static int countTriplets(int n, string s)
{
// Stores the count of triplets.
int ans = 0;
// Iterate over all the triplets.
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
for (int k = j + 1; k < n; ++k) {
// Extract integer from 'S[i]',
// 'S[j]', 'S[k]'.
int x = s[i];
int y = s[j], z = s[k];
// If condition 'S[i]' & 'S[j]'
// == 'S[j]' &'S[k]' is true,
// increment 'ans'.
if ((x & y) == (y & z)) {
ans++;
}
}
}
}
// Return the answer
return ans;
}
// Driver code
static public void Main ()
{
int N = 4;
string S = "0010";
// Function call
Console.Write(countTriplets(N, S));
}
}
// This code is contributed by hrithikgarg03188.
Javascript
C++
// C++ program for above approach
#include
using namespace std;
// Function to count number of triplets
int countTriplets(int n, string& s)
{
// Stores the count of triplets.
int ans = 0;
// 'pre[i]', 'suf[i]', stores the
// number of zeroes in
// the prefix and suffix
vector pre(n), suf(n);
// Build the prefix array
for (int i = 0; i < n; ++i) {
pre[i] = (i == 0 ? 0 : pre[i - 1])
+ (s[i] == '0');
}
// Build the suffix array.
for (int i = n - 1; i >= 0; --i) {
suf[i]
= (i == n - 1 ? 0 : suf[i + 1])
+ (s[i] == '0');
}
// Iterate over the middle index
// of the triplet.
for (int j = 1; j < n - 1; ++j) {
// If 'S[j]' == '0'
if (s[j] == '0') {
ans += j * (n - j - 1);
}
else {
// If 'S[j]' == '1'
ans += pre[j - 1] * suf[j + 1]
+ (j - pre[j - 1])
* (n - j - 1 - suf[j + 1]);
}
}
// Return the answer.
return ans;
}
// Driver code
int main()
{
int N = 4;
string S = "0010";
// Function call
cout << countTriplets(N, S);
return 0;
}
4
时间复杂度: O(N 3 )
辅助空间: O(1)
有效方法:有效解决问题的想法基于以下观察:
观察:
- Since S[i] ∈ {0, 1}, there can be only 8 possible distinct triplets. Let’s analyze how many of these actually satisfy the condition S[i] & S[j] == S[j] & S[k].
S[i] | S[j] | S[k] | S[i]&S[j]==S[j]&S[k] |
0 | 0 | 0 | 1 |
0 | 0 | 1 | 1 |
0 | 1 | 0 | 1 |
0 | 1 | 1 | 0 |
1 | 0 | 0 | 1 |
1 | 0 | 1 | 1 |
1 | 1 | 0 | 0 |
1 | 1 | 1 | 1 |
- After analyzing the truth table, observe that whenever S[j] == ‘0’, the condition is always satisfied. Also, when S[j] == ‘1’, then both S[i] and S[k] should be the same.
- Thus, iterate over all the S[j] values, and depending on the value of S[j], simply count the number of triplets.
- If S[j] == ‘0’, then S[i] and S[k] can be anything, So total possible ways of choosing any i and k is j * (N – j – 1).
- Otherwise, if S[j] == ‘1’, then S[i] and S[k] should be same. So only 0s can make pair with 0s and 1s with 1s. Say there was x1 0s in prefix and x2 0s in suffix and y1 and y2 1s in prefix and suffix. Then total possible pairs are x1*x2 + y1*y2
请按照以下步骤解决此问题:
- 声明一个变量(比如ans ) 存储三元组的计数并将其初始化为 0。
- 创建一个前缀数组pre和一个后缀数组suf 。这两个数组在数组的前缀和后缀中存储了零的数量。
- 对于构建前缀数组,从0 迭代到 N – 1 :
- 如果 S[i] == '0',则 pre[i] = pre[i – 1] + 1。
- 如果 S[i]== '1',则 pre[i] = pre[i – 1]。
- 对于构建后缀数组,从N – 1 迭代到 0 :
- 如果 S[i] == '0',则 suf[i] = suf[i + 1] + 1。
- 如果 S[i] == '1',则 suf[i] = suf[i + 1]。
- 现在再次迭代,从1 到 N – 2 (我们正在迭代 S[j]):
- 如果 S[j] == '0',则根据观察将 j * (N – j – 1)添加到ans变量中。
- 如果 S[j] == '1',则添加 'pre[j - 1]' * 'suf[j + 1]' + (j - 'pre[j - 1]') * (N - j - 1 – 'suf[j + 1]')到 ans 根据上述观察。
- 现在返回ans变量,因为它包含三元组的最终计数。
以下是上述方法的实现:
C++
// C++ program for above approach
#include
using namespace std;
// Function to count number of triplets
int countTriplets(int n, string& s)
{
// Stores the count of triplets.
int ans = 0;
// 'pre[i]', 'suf[i]', stores the
// number of zeroes in
// the prefix and suffix
vector pre(n), suf(n);
// Build the prefix array
for (int i = 0; i < n; ++i) {
pre[i] = (i == 0 ? 0 : pre[i - 1])
+ (s[i] == '0');
}
// Build the suffix array.
for (int i = n - 1; i >= 0; --i) {
suf[i]
= (i == n - 1 ? 0 : suf[i + 1])
+ (s[i] == '0');
}
// Iterate over the middle index
// of the triplet.
for (int j = 1; j < n - 1; ++j) {
// If 'S[j]' == '0'
if (s[j] == '0') {
ans += j * (n - j - 1);
}
else {
// If 'S[j]' == '1'
ans += pre[j - 1] * suf[j + 1]
+ (j - pre[j - 1])
* (n - j - 1 - suf[j + 1]);
}
}
// Return the answer.
return ans;
}
// Driver code
int main()
{
int N = 4;
string S = "0010";
// Function call
cout << countTriplets(N, S);
return 0;
}
4
时间复杂度: O(N)
辅助空间: O(N)