统计盈利目标区间(Py/Java/C/C++/Js/Go)题解
华为OD机试新系统真题 华为OD上机考试新系统真题 6月3号 100分题型
华为OD机试新系统真题目录点击查看: 华为OD机试新系统真题题库目录|机考题库 + 算法考点详解
题目内容
某公司的财务流水系统重构为实时流处理架构。日盈利数据(可正可负)作为消息一条条实时推送。 请设计一个实时监控模块,它接收两个序列:操作指令序列
o
p
s
\\ ops
ops 和对应的参数序列
v
a
l
s
\\ vals
vals。
o
p
s
[
i
]
\\ ops[i]
ops[i] == “
a
d
d
add
add” 时:代表接收一条新的日盈利流数据,其值为
v
a
l
s
[
i
]
\\ vals[i]
vals[i]。
o
p
s
[
i
]
\\ ops[i]
ops[i] == “
q
u
e
r
y
query
query” 时:代表发起一次实时查询,目标值为
v
a
l
s
[
i
]
\\ vals[i]
vals[i](即
t
a
r
g
e
t
\\ target
target)。要求立刻返回:以当前最新到达的这笔流水为区间右端点,且区间总和恰好等于
t
a
r
g
e
t
\\ target
target 的连续区间个数。
输入描述
-
o
p
s
ops
ops:字符串数组,表示操作指令序列。 -
v
a
l
s
vals
vals:整型数组,表示与o
p
s
ops
ops 一一对应的参数序列。对于a
d
d
add
add 指令,代表盈利值;对于q
u
e
r
y
query
query 指令,代表目标值t
a
r
g
e
t
target
target。
输出描述
返回一个整型数组,按照
q
u
e
r
y
query
query 指令出现的顺序,依次保存每次查询的结果,如果没有
q
u
e
r
y
query
query ,返回空数组,如果
q
u
e
r
y
query
query 没有符合条件的区间,返回
0
0
0 。
约束条件
o
p
s
ops
ops 中仅包含"
a
d
d
add
add “和”
q
u
e
r
y
query
query ",
o
p
s
.
l
e
n
g
t
h
<
=
10
5
ops.length <= 10^5
ops.length<=105
−
10
4
<
=
v
a
l
u
e
s
[
i
]
<
=
10
4
-10^4 <= values[i] <= 10^4
−104<=values[i]<=104 当操作作为
a
d
d
add
add
−
10
9
<
=
v
a
l
u
e
s
[
i
]
<
=
10
9
-10^9 <= values[i] <= 10^9
−109<=values[i]<=109 当操作作为
q
u
e
r
y
query
query
样例1
输入
add,add,query,add,query
1,2,3,3,6
输出
1,1
说明
-
a
d
d
add
add1
1
1:流为[
1
]
[1]
[1] -
a
d
d
add
add2
2
2:流为[
1
,
2
]
[1,2]
[1,2] -
q
u
e
r
y
query
query3
3
3:最新数据是2
2
2。以2
2
2 结尾且和为3
3
3 的区间只有[
1
,
2
]
[1,2]
[1,2],返回1
1
1。 -
a
d
d
add
add3
3
3:流为[
1
,
2
,
3
]
[1,2,3]
[1,2,3] -
q
u
e
r
y
query
query6
6
6:最新数据是3
3
3。以3
3
3 结尾且和为6
6
6 的区间只有[
1
,
2
,
3
]
[1,2,3]
[1,2,3],返回1
1
1。
样例2
输入
add,add,add,query,add,add,query
1,-1,0,0,1,-1,0
输出
2,3
说明
- 前三次
a
d
d
add
add 后,流为[
1
,
−
1
,
0
]
[1,-1,0]
[1,−1,0]。 - 第一个
q
u
e
r
y
query
query0
0
0:以最新元素0
0
0 结尾,和为0
0
0 的区间有[
0
]
[0]
[0] 和[
1
,
−
1
,
0
]
[1,-1,0]
[1,−1,0],返回2
2
2 。 - 后两次
a
d
d
add
add 后,流为[
1
,
−
1
,
0
,
1
,
−
1
]
[1,-1,0,1,-1]
[1,−1,0,1,−1]。 - 第二个
q
u
e
r
y
query
query0
0
0:以最新元素−
1
-1
−1 结尾,和为0
0
0 的区间有[
1
,
−
1
]
、
[
0
,
1
,
−
1
]
、
[
1
,
−
1
,
0
,
1
,
−
1
]
[1,-1]、[0,1,-1]、[1,-1,0,1,-1]
[1,−1]、[0,1,−1]、[1,−1,0,1,−1],返回3
3
3。
题解
思路:前缀和
- op = add, 更新prefix += val, 对应前缀和数量 + 1
- op = query是,查询指定前缀和为prefix – va的数量加入ans
c++
#include<bits/stdc++.h>
#include <unordered_map>
#include <vector>
using namespace std;
// 通用 切割函数 函数 将字符串str根据delimiter进行切割
vector<string> split(const string& str, const string& delimiter) {
vector<string> result;
size_t start = 0;
size_t end = str.find(delimiter);
while (end != string::npos) {
result.push_back(str.substr(start, end – start));
start = end + delimiter.length();
end = str.find(delimiter, start);
}
// 添加最后一个部分
result.push_back(str.substr(start));
return result;
}
vector<int> handle(vector<string>& ops, vector<int>& value) {
// 前缀和
long prefix = 0;
// 记录指定前缀和出现次数
unordered_map<long, int> prefixCount;
int n = ops.size();
vector<int> ans;
for (int i = 0; i < n; i++) {
int val = value[i];
if (ops[i] == "add") {
prefix += val;
// 指定前缀和次数
prefixCount[prefix]++;
} else if (ops[i] == "query") {
long target = prefix – val;
ans.push_back(prefixCount[target]);
}
}
return ans;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
string opsStr, valueStr;
getline(cin, opsStr);
getline(cin, valueStr);
vector<string> ops = split(opsStr, ",");
vector<string> valuePart = split(valueStr, ",");
vector<int> value;
for (auto str : valuePart) {
value.push_back(stoi(str));
}
vector<int> ans = handle(ops, value);
// 处理结果
for (int i = 0; i < ans.size(); i++) {
if (i != 0) {
cout << ",";
}
cout << ans[i];
}
return 0;
}
Java
import java.util.*;
public class Main {
static List<Integer> handle(String[] ops, int[] value) {
// 当前前缀和
long prefix = 0;
// 指定前缀和出现数量
Map<Long, Integer> prefixCount = new HashMap<>();
List<Integer> ans = new ArrayList<>();
int n = ops.length;
for (int i = 0; i < n; i++) {
int val = value[i];
if (ops[i].equals("add")) {
prefix += val;
prefixCount.put(prefix, prefixCount.getOrDefault(prefix, 0) + 1);
} else if (ops[i].equals("query")) {
long target = prefix – val;
ans.add(prefixCount.getOrDefault(target, 0));
}
}
return ans;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String opsStr = sc.nextLine();
String valueStr = sc.nextLine();
String[] ops = opsStr.split(",");
String[] valuePart = valueStr.split(",");
int[] value = new int[valuePart.length];
for (int i = 0; i < valuePart.length; i++) {
value[i] = Integer.parseInt(valuePart[i]);
}
List<Integer> ans = handle(ops, value);
for (int i = 0; i < ans.size(); i++) {
if (i > 0) System.out.print(",");
System.out.print(ans.get(i));
}
}
}
Python
import sys
def handle(ops, value):
# 当前前缀和
prefix = 0
# 指定前缀和出现数量
prefix_count = {}
ans = []
for op, val in zip(ops, value):
if op == "add":
prefix += val
prefix_count[prefix] = prefix_count.get(prefix, 0) + 1
else: # query
target = prefix – val
ans.append(prefix_count.get(target, 0))
return ans
def main():
ops_str = sys.stdin.readline().strip()
value_str = sys.stdin.readline().strip()
ops = ops_str.split(",")
value = list(map(int, value_str.split(",")))
ans = handle(ops, value)
print(",".join(map(str, ans)))
if __name__ == "__main__":
main()
JavaScript
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const lines = [];
rl.on("line", (line) => {
lines.push(line.trim());
});
rl.on("close", () => {
const ops = lines[0].split(",");
const value = lines[1].split(",").map(Number);
// 当前前缀和
let prefix = 0;
// 记录前缀和出现次数
const prefixCount = new Map();
const ans = [];
for (let i = 0; i < ops.length; i++) {
const val = value[i];
if (ops[i] === "add") {
prefix += val;
prefixCount.set(prefix, (prefixCount.get(prefix) || 0) + 1);
} else {
const target = prefix – val;
ans.push(prefixCount.get(target) || 0);
}
}
console.log(ans.join(","));
});
Go
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func handle(ops []string, value []int) []int {
// 当前前缀和
prefix := int64(0)
// 指定前缀和出现数量
prefixCount := make(map[int64]int)
ans := []int{}
for i := 0; i < len(ops); i++ {
val := value[i]
if ops[i] == "add" {
prefix += int64(val)
prefixCount[prefix]++
} else {
target := prefix – int64(val)
ans = append(ans, prefixCount[target])
}
}
return ans
}
func main() {
reader := bufio.NewReader(os.Stdin)
opsStr, _ := reader.ReadString('\\n')
valueStr, _ := reader.ReadString('\\n')
opsStr = strings.TrimSpace(opsStr)
valueStr = strings.TrimSpace(valueStr)
ops := strings.Split(opsStr, ",")
valueParts := strings.Split(valueStr, ",")
value := make([]int, len(valueParts))
for i := range valueParts {
v, _ := strconv.Atoi(valueParts[i])
value[i] = v
}
ans := handle(ops, value)
for i := range ans {
if i > 0 {
fmt.Print(",")
}
fmt.Print(ans[i])
}
}
C语言
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define OFFSET 1000000000
#define SIZE 2000000001 // 理论值域 [-1e9, 1e9]
static int *cnt;
int main() {
char opsStr[1000000], valueStr[1000000];
fgets(opsStr, sizeof(opsStr), stdin);
fgets(valueStr, sizeof(valueStr), stdin);
opsStr[strcspn(opsStr, "\\n")] = 0;
valueStr[strcspn(valueStr, "\\n")] = 0;
cnt = (int*)calloc(SIZE, sizeof(int));
char *ops[100000];
int value[100000];
int n = 0;
// 解析 ops
char *token = strtok(opsStr, ",");
while (token) {
ops[n++] = token;
token = strtok(NULL, ",");
}
int m = 0;
token = strtok(valueStr, ",");
while (token) {
value[m++] = atoi(token);
token = strtok(NULL, ",");
}
long prefix = 0;
int first = 1;
for (int i = 0; i < n; i++) {
if (strcmp(ops[i], "add") == 0) {
prefix += value[i];
int idx = (int)(prefix + OFFSET);
cnt[idx]++;
} else {
long target = prefix – value[i];
int idx = (int)(target + OFFSET);
int res = cnt[idx];
if (!first) printf(",");
printf("%d", res);
first = 0;
}
}
free(cnt);
return 0;
}