Implement a simplified logging system that supports log ingestion and conditional queries. Each operation is one of the following strings:
ADD timestamp service level message: append one log entryQUERY startTs endTs serviceOr* levelOr* keywordOr*: count matching logs A log matches a query ifstartTs ≤ timestamp ≤ endTs,serviceandlevelmatch exactly unless the filter is*, andkeywordappears as a substring of the message unless the filter is*. Process all operations in order and return the outputs produced by theQUERYcommands. Function Description Complete the functionrunLogIngestionQueriesin the editor below.runLogIngestionQuerieshas the following parameter:String[] operations: the operations to execute in order Returnsint[]: the counts produced by theQUERYoperations.
Constraints
1 ≤ operations.length ≤ 2 * 10⁵- Timestamps are non-negative integers.
serviceandlevelcontain no spaces.messagemay contain spaces and is matched by substring search.
Example 1
Input:
operations = ["ADD 1 api INFO hello world", "ADD 2 api ERROR something failed", "ADD 3 web INFO user login", "QUERY 1 3 * * *", "QUERY 1 2 api * *", "QUERY 2 3 api ERROR failed"]
Output:
[3, 2, 1]
Explanation:
The three queries count all logs, then all api logs in the first two timestamps, then only the single error log whose message contains failed.
Example 2
Input:
operations = ["ADD 1 api INFO login ok", "ADD 2 api INFO logout ok", "ADD 3 api INFO login failed", "QUERY 1 3 api INFO login", "QUERY 1 3 api INFO ok", "QUERY 1 2 api INFO login", "QUERY 3 3 api INFO login"]
Output:
[2, 2, 1, 1]
Explanation:
Substring matching on the message field allows both successful and failed login events to match the keyword login.
解法
朴素扫描即可:维护一个日志列表(时间戳、service、level、message),每次 QUERY 遍历所有日志,按时间范围和三个过滤条件(* 代表通配)逐条匹配,keyword 用子串检测。设总操作数 O,每个 QUERY 最坏 O(O · L),整体 O(O² · L),L 为 message 长度;对 2·10⁵ 在 OA 环境通常够用。
from typing import List
def runLogIngestionQueries(operations: List[str]) -> List[int]:
logs: list[tuple[int, str, str, str]] = []
results: List[int] = []
for op in operations:
if op.startswith("ADD "):
parts = op.split(" ", 4)
ts = int(parts[1])
logs.append((ts, parts[2], parts[3], parts[4]))
else:
parts = op.split(" ", 5)
start, end = int(parts[1]), int(parts[2])
svc_f, lvl_f, kw_f = parts[3], parts[4], parts[5]
cnt = 0
for ts, svc, lvl, msg in logs:
if ts < start or ts > end:
continue
if svc_f != "*" and svc != svc_f:
continue
if lvl_f != "*" and lvl != lvl_f:
continue
if kw_f != "*" and kw_f not in msg:
continue
cnt += 1
results.append(cnt)
return resultsimport java.util.*;
class Solution {
int[] runLogIngestionQueries(String[] operations) {
List<long[]> tsAndIdx = new ArrayList<>();
List<String[]> logs = new ArrayList<>();
List<Integer> results = new ArrayList<>();
for (String op : operations) {
if (op.startsWith("ADD ")) {
String[] parts = op.split(" ", 5);
logs.add(new String[]{parts[1], parts[2], parts[3], parts[4]});
} else {
String[] parts = op.split(" ", 6);
long start = Long.parseLong(parts[1]), end = Long.parseLong(parts[2]);
String svcF = parts[3], lvlF = parts[4], kwF = parts[5];
int cnt = 0;
for (String[] log : logs) {
long ts = Long.parseLong(log[0]);
if (ts < start || ts > end) continue;
if (!svcF.equals("*") && !log[1].equals(svcF)) continue;
if (!lvlF.equals("*") && !log[2].equals(lvlF)) continue;
if (!kwF.equals("*") && !log[3].contains(kwF)) continue;
cnt++;
}
results.add(cnt);
}
}
int[] out = new int[results.size()];
for (int i = 0; i < out.length; i++) out[i] = results.get(i);
return out;
}
}#include <vector>
#include <string>
#include <sstream>
class Solution {
public:
std::vector<int> runLogIngestionQueries(std::vector<std::string>& operations) {
std::vector<std::tuple<long long, std::string, std::string, std::string>> logs;
std::vector<int> results;
for (auto& op : operations) {
std::stringstream ss(op);
std::string head; ss >> head;
if (head == "ADD") {
long long ts; std::string svc, lvl; ss >> ts >> svc >> lvl;
std::string msg; std::getline(ss, msg);
if (!msg.empty() && msg[0] == ' ') msg.erase(0, 1);
logs.push_back({ts, svc, lvl, msg});
} else {
long long start, end; std::string svcF, lvlF, kwF;
ss >> start >> end >> svcF >> lvlF >> kwF;
int cnt = 0;
for (auto& [ts, svc, lvl, msg] : logs) {
if (ts < start || ts > end) continue;
if (svcF != "*" && svc != svcF) continue;
if (lvlF != "*" && lvl != lvlF) continue;
if (kwF != "*" && msg.find(kwF) == std::string::npos) continue;
cnt++;
}
results.push_back(cnt);
}
}
return results;
}
};