#P3320. 第1题-算01
-
1000ms
Tried: 72
Accepted: 36
Difficulty: 2
所属公司 :
科大讯飞
时间 :2025年7月26日
-
算法标签>前缀和
第1题-算01
解题思路
给定长度为 n 的 01 串 s=s1s2…sn,要求对每个位置 i,统计在它左侧(下标 <i)与 si 不同的字符个数。 我们可以采用前缀计数的方法:
-
定义两个变量
cnt0和cnt1,分别记录当前已遍历字符中'0'和'1'的个数。 -
对每个位置 i:
- 若 si=′0′,则左侧与它不同的字符即为所有已出现的
'1',即 ai=cnt1; - 若 si=′1′,则 ai=cnt0。
- 若 si=′0′,则左侧与它不同的字符即为所有已出现的
-
将对应的计数器自增:若 si=′0′,则
cnt0++;若 si=′1′,则cnt1++。
这种方法只需一次扫描,时间复杂度 O(n),空间复杂度 O(1)。
算法步骤
-
初始化
cnt0=0, cnt1=0,并准备数组ans长度为 n。 -
从 i=1 到 n 依次遍历:
- 如果 si=′0′,则
ans[i]=cnt1,同时cnt0++; - 否则
ans[i]=cnt0,同时cnt1++。
- 如果 si=′0′,则
-
输出
ans数组。
复杂度分析
- 时间复杂度:遍历一次字符串,进行常数次操作,故为 O(n)。
- 空间复杂度:只使用常数个额外变量与输出数组,故为 O(n)。
代码实现
Python
def count_diff(s):
n = len(s)
ans = [0] * n
cnt0, cnt1 = 0, 0
for i, ch in enumerate(s):
if ch == '0':
ans[i] = cnt1 # 左侧所有 '1'
cnt0 += 1 # 更新 '0' 计数
else:
ans[i] = cnt0 # 左侧所有 '0'
cnt1 += 1 # 更新 '1' 计数
return ans
if __name__ == '__main__':
T = int(input().strip())
for _ in range(T):
n = int(input().strip())
s = input().strip()
res = count_diff(s)
print(' '.join(map(str, res)))
Java
import java.util.Scanner;
public class Main {
// 计算每个位置左侧与当前字符不同的数量
static int[] countDiff(String s) {
int n = s.length();
int[] ans = new int[n];
int cnt0 = 0, cnt1 = 0;
for (int i = 0; i < n; i++) {
char c = s.charAt(i);
if (c == '0') {
ans[i] = cnt1; // 左侧所有 '1'
cnt0++; // 更新 '0' 计数
} else {
ans[i] = cnt0; // 左侧所有 '0'
cnt1++; // 更新 '1' 计数
}
}
return ans;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
while (T-- > 0) {
int n = sc.nextInt();
String s = sc.next();
int[] res = countDiff(s);
for (int i = 0; i < n; i++) {
System.out.print(res[i] + (i+1<n ? " " : ""));
}
System.out.println();
}
sc.close();
}
}
C++
#include <bits/stdc++.h>
using namespace std;
// 计算每个位置左侧与当前字符不同的数量
vector<int> countDiff(const string &s) {
int n = s.size();
vector<int> ans(n);
int cnt0 = 0, cnt1 = 0;
for (int i = 0; i < n; i++) {
if (s[i] == '0') {
ans[i] = cnt1; // 左侧所有 '1'
cnt0++; // 更新 '0' 计数
} else {
ans[i] = cnt0; // 左侧所有 '0'
cnt1++; // 更新 '1' 计数
}
}
return ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n;
string s;
cin >> n >> s;
vector<int> res = countDiff(s);
for (int i = 0; i < n; i++) {
cout << res[i] << (i+1<n ? ' ' : '\n');
}
}
return 0;
}
题目内容
牛牛拥有一个长度为n的01串s=“s1s2...sn”(下标从1开始)。
对于每个位置i(1≤i≤n),定义:
-
ai为在i左侧(即下标<i的位置)中,字符与si不同的元素个数。
请你输出整个序列{a1,a2,...an}
输入描述
每个测试文件均包含多组测试数据。第一行输入一个整数T(1≤T≤100)代表数据组数,每组测试数据描述如下:
在第一行输入一个整数n(1≤n≤103),表示字符串长度。
在第二行输入一个长度为n,仅由字符'0'和'1'组成的字符串s,表示初始字符串。
输出描述
于每组测试数据,新起一行,按顺序输出n个整数a1,a2,...,an相邻整数之间用一个空格分隔。
样例1
输入
2
4
1101
5
01010
输出
0 0 2 1
0 1 1 2 2
说明
对于第一组测试数据:
- 位置1:左侧无字符,a1=0;
- 位置2:左侧只有'1',与s2='1'相同,a2=0;
- 位置3:s3='0'左侧有两个'1',故a3=2:
- 位置4:s4='1',左侧有一个'0',故a4=1。