API请求日志去重分析
华为OD机试真题 华为OD上机考试真题 4月15号 100分题型
华为OD机试真题目录点击查看: 华为OD机试真题题库目录|机考题库 + 算法考点详解
题目描述
某微服务系统的日志监控平台需要分析 API调用记录。日志中包含大量重复的请求记录,为了优化存储和后续分析,需要对相邻的重复请求进行合并统计。
具体规则如下:
1.日志按时间顺序排列,每条记录包含请求路径和响应时间
2.如果连续出现相同的请求路径,需要将这些记录合并为一条
3.合并后的记录需要统计该路径连续出现的次数,并保留所有响应时间的平均值
4.相同路径但被其他路径分隔的,视为不同的记录组,需要分别合并
请实现一个函数,对给定的日志数据进行去重合并处理。
输入描述
输入请求路径path数组,按时间顺序排列
输入对应的响应时间responseTimes数组(毫秒)
补充
0≤paths.length≤10^50≤responseTimes.length≤10^5paths.length==responseTimes.length1≤responseTimes[i]≤10^4- 路径长度不超过 100个字符
输出描述
按顺序输出每个记录组信息,每个记录组包含以下三个元素
- 该路径在输入数组中首次出现索引
- 该路径连续出现的次数
- 该组路径的平均响应时间(向下取整)
用例1
输入
none
/api/user,/api/user,/api/order,/api/user,/api/order,/api/order
100,200,150,300,250,350
输出
none
0,2,150 2,1,150 3,1,300 4,2,300
说明
/api/user在索引0-1连续出现,平均响应时间为150
/api/order在索引2单独出现,平均响应时间为150
api/user在索引3单独出现,由于被分割,响应时间为300
/api/order在索引 4−5 连续出现 2 次,平均响应时间:(250+350)/2=300
题解
思路:双指针
- 使用双指针统计每个相同请求地址的{起始位置,终止位置}并累加计算区域内总响应时间。
- 根据1的逻辑可以得出每条记录的{首次索引,连续次数,平均响应时间},按顺序保存在结果数组中
- 返回结果数组即可
c++
c++
#include<iostream>
#include<vector>
#include<string>
#include <utility>
#include <sstream>
#include<algorithm>
#include<cmath>
#include<map>
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<vector<int>> hanle(vector<string> path, vector<int> responseTime) {
vector<vector<int>> res;
int n = path.size();
for (int i = 0; i < n; ) {
int totalTime = responseTime[i];
int j = i;
// 获取相同路径起始和终止连续位置
while (j + 1< n && path[j] == path[j+1]) {
totalTime += responseTime[j+1];
j++;
}
res.push_back({i, j - i + 1, totalTime / (j - i + 1)});
i = j + 1;
}
return res;
}
int main() {
string pathInput;
string responseInput;
getline(cin, pathInput);
getline(cin, responseInput);
vector<string> paths = split(pathInput, ",");
vector<int> responseTime(paths.size());
vector<string> tmp = split(responseInput, ",");
for (int i = 0; i < tmp.size(); i++) {
responseTime[i] = stoi(tmp[i]);
}
vector<vector<int>> res = hanle(paths, responseTime);
// 输出结果
for (int i = 0; i < res.size(); i++) {
cout << res[i][0] << "," << res[i][1] << "," << res[i][2];
if (i != res.size() -1) {
cout << " ";
}
}
return 0;
}
JAVA
JAVA
import java.util.*;
public class Main {
// 统计函数
static List<int[]> hanle(List<String> path, List<Integer> responseTime) {
List<int[]> res = new ArrayList<>();
int n = path.size();
for (int i = 0; i < n;) {
int totalTime = responseTime.get(i);
int j = i;
// 获取相同路径起始和终止连续位置
while (j + 1 < n && path.get(j).equals(path.get(j + 1))) {
totalTime += responseTime.get(j + 1);
j++;
}
res.add(new int[]{i, j - i + 1, totalTime / (j - i + 1)});
i = j + 1;
}
return res;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String pathInput = sc.nextLine();
String responseInput = sc.nextLine();
String[] pathsArr = pathInput.split(",");
String[] responseArr = responseInput.split(",");
List<String> paths = Arrays.asList(pathsArr);
List<Integer> responseTime = new ArrayList<>();
for (String s : responseArr) {
responseTime.add(Integer.parseInt(s));
}
List<int[]> res = hanle(paths, responseTime);
for (int i = 0; i < res.size(); i++) {
int[] r = res.get(i);
System.out.print(r[0] + "," + r[1] + "," + r[2]);
if (i != res.size() - 1) System.out.print(" ");
}
}
}
Python
python
import sys
# 统计函数
def hanle(path, response_time):
res = []
n = len(path)
i = 0
while i < n:
total_time = response_time[i]
j = i
# 获取相同路径起始和终止连续位置
while j + 1 < n and path[j] == path[j + 1]:
total_time += response_time[j + 1]
j += 1
res.append([i, j - i + 1, total_time // (j - i + 1)])
i = j + 1
return res
if __name__ == "__main__":
path_input = sys.stdin.readline().strip()
response_input = sys.stdin.readline().strip()
paths = path_input.split(",")
response_time = list(map(int, response_input.split(",")))
res = hanle(paths, response_time)
print(" ".join(f"{r[0]},{r[1]},{r[2]}" for r in res))
JavaScript
js
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let input = [];
rl.on("line", (line) => {
input.push(line.trim());
});
rl.on("close", () => {
let pathInput = input[0];
let responseInput = input[1];
let paths = pathInput.split(",");
let responseTime = responseInput.split(",").map(Number);
function hanle(path, responseTime) {
let res = [];
let n = path.length;
for (let i = 0; i < n;) {
let totalTime = responseTime[i];
let j = i;
// 获取相同路径起始和终止连续位置
while (j + 1 < n && path[j] === path[j + 1]) {
totalTime += responseTime[j + 1];
j++;
}
res.push([i, j - i + 1, Math.floor(totalTime / (j - i + 1))]);
i = j + 1;
}
return res;
}
let res = hanle(paths, responseTime);
console.log(res.map(r => `${r[0]},${r[1]},${r[2]}`).join(" "));
});
Go
go
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
// 统计函数
func hanle(path []string, responseTime []int) [][]int {
res := [][]int{}
n := len(path)
for i := 0; i < n; {
totalTime := responseTime[i]
j := i
// 获取相同路径起始和终止连续位置
for j+1 < n && path[j] == path[j+1] {
totalTime += responseTime[j+1]
j++
}
res = append(res, []int{i, j - i + 1, totalTime / (j - i + 1)})
i = j + 1
}
return res
}
func main() {
reader := bufio.NewReader(os.Stdin)
pathInput, _ := reader.ReadString('\n')
responseInput, _ := reader.ReadString('\n')
// 去掉换行符
pathInput = strings.TrimSpace(pathInput)
responseInput = strings.TrimSpace(responseInput)
paths := strings.Split(pathInput, ",")
tmp := strings.Split(responseInput, ",")
responseTime := make([]int, len(tmp))
for i := 0; i < len(tmp); i++ {
fmt.Sscanf(tmp[i], "%d", &responseTime[i])
}
res := hanle(paths, responseTime)
for i := 0; i < len(res); i++ {
fmt.Printf("%d,%d,%d", res[i][0], res[i][1], res[i][2])
if i != len(res)-1 {
fmt.Print(" ")
}
}
}
C语言
cpp
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// 统计函数
void hanle(char path[][100], int pathSize, int responseTime[],
int res[][3], int *resSize) {
int k = 0;
for (int i = 0; i < pathSize;) {
int totalTime = responseTime[i];
int j = i;
// 获取相同路径起始和终止连续位置
while (j + 1 < pathSize && strcmp(path[j], path[j + 1]) == 0) {
totalTime += responseTime[j + 1];
j++;
}
res[k][0] = i;
res[k][1] = j - i + 1;
res[k][2] = totalTime / (j - i + 1);
k++;
i = j + 1;
}
*resSize = k;
}
int main() {
char pathInput[10300000], responseInput[10300000];
fgets(pathInput, sizeof(pathInput), stdin);
fgets(responseInput, sizeof(responseInput), stdin);
// 去掉换行
pathInput[strcspn(pathInput, "\n")] = 0;
responseInput[strcspn(responseInput, "\n")] = 0;
char path[100005][100];
int responseTime[100005];
int pathSize = 0;
char *token = strtok(pathInput, ",");
while (token) {
strcpy(path[pathSize++], token);
token = strtok(NULL, ",");
}
int i = 0;
token = strtok(responseInput, ",");
while (token) {
responseTime[i++] = atoi(token);
token = strtok(NULL, ",");
}
int res[100005][3], resSize = 0;
hanle(path, pathSize, responseTime, res, &resSize);
for (int i = 0; i < resSize; i++) {
printf("%d,%d,%d", res[i][0], res[i][1], res[i][2]);
if (i != resSize - 1) printf(" ");
}
return 0;
}