日志关键词统计(C/C++/Py/Java/Js/Go)题解
华为OD机试新系统真题 华为OD上机考试新系统真题 6月21号 100分题型
华为OD机试新系统真题目录点击查看: 华为OD机试新系统真题题库目录|机考题库 + 算法考点详解
题目内容
给定日志字符串数组
l
o
g
s
logs
logs 和关键词数组
k
e
y
w
o
r
d
s
keywords
keywords,统计每个关键词在所有日志中出现的总次数,并找出经常一起出现的关键词组合(至少在
2
2
2 条日志中同时出现)。
注意:
2
2
2 条不同日志中同时出现才算"经常关联"
k
e
y
w
o
r
d
s
.
l
e
n
g
t
h
keywords.length
keywords.length 个元素为关键词出现次数,后续元素每两个一组表示关联组合索引(索引小的在前,索引大的在后);多个组合时先按第一个索引升序,再按第二个索引升序
数据规模:
1
≤
l
o
g
s
1 \\le logs
1≤logs.length
≤
1000
\\le 1000
≤1000,
1
≤
k
e
y
w
o
r
d
s
1 \\le keywords
1≤keywords.length
≤
100
\\le 100
≤100,每条日志长度
≤
1000
\\le 1000
≤1000 字符
输入描述
第一行输入n m,其中n表示日志数量.m表示关键词数量
接下来n行,每行代表一条日志
接下来m行,每行代表一条关键词
输出描述
输出结果,使用,进行分割。
样例1
输入
3 2
Error in system
warning: error detected
No errors found
error
warning
输出
2,1
说明 关键词统计:
e
r
r
o
r
error
error 出现
2
2
2 次,
w
a
r
n
i
n
g
warning
warning 出现
1
1
1 次 关联分析:
e
r
r
o
r
error
error 和
w
a
r
n
i
n
g
warning
warning 只在第
2
2
2 条日志中同时出现
1
1
1 次,未达到至少
2
2
2 次共现的标准,因此无关联组合输出
样例2
输入
4 4
Error: system failure
Warning: error in network
System error detected again
Network warning error found
error
system
warning
network
输出
4,2,2,2,0,1,0,2,0,3,2,3
说明 关键词统计:
e
r
r
o
r
error
error 出现
4
4
4 次,
s
y
s
t
e
m
system
system 出现
2
2
2 次,
w
a
r
n
i
n
g
warning
warning 出现
2
2
2 次,
n
e
t
w
o
r
k
network
network 出现
2
2
2 次 关联组合:
- (
e
r
r
o
r
,
s
y
s
t
e
m
error, system
error,system):在第1
1
1、3
3
3 条日志中同时出现,共现2
2
2 次→
→
→ 输出[
0
,
1
]
[0,1]
[0,1] - (
e
r
r
o
r
,
w
a
r
n
i
n
g
error, warning
error,warning):在第2
2
2、4
4
4 条日志中同时出现,共现2
2
2 次→
→
→ 输出[
0
,
2
]
[0,2]
[0,2] - (
e
r
r
o
r
,
n
e
t
w
o
r
k
error, network
error,network):在第2
2
2、3
3
3、4
4
4 条日志中同时出现,共现3
3
3次→
→
→ 输出[
0
,
3
]
[0,3]
[0,3] - (
w
a
r
n
i
n
g
,
n
e
t
w
o
r
k
warning, network
warning,network):在第2
2
2、4
4
4 条日志中同时出现,共现2
2
2 次→
→
→ 输出[
2
,
3
]
[2,3]
[2,3] 最终结果:统计次数[
4
,
2
,
2
,
2
]
[4,2,2,2]
[4,2,2,2] + 关联组合索引[
0
,
1
,
0
,
2
,
0
,
3
,
2
,
3
]
[0,1,0,2,0,3,2,3]
[0,1,0,2,0,3,2,3]
样例3
输入
4 2
Error in module A
Module error B error
Error module C error
Module error D
error
module
输出
6,4,0,1
说明 关键词统计:
e
r
r
o
r
error
error 出现
6
6
6 次(第
1
1
1 条
1
1
1 次,第
2
2
2 条
2
2
2 次,第
3
3
3 条
2
2
2 次,第
4
4
4 条
1
1
1 次),
m
o
d
u
l
e
module
module 出现
4
4
4 次 关联组合:(
e
r
r
o
r
,
m
o
d
u
l
e
error, module
error,module)在第
1
1
1、
2
2
2、
3
3
3、
4
4
4 条日志中都同时出现,共现
4
4
4 次
→
→
→ 输出
[
0
,
1
]
[0,1]
[0,1] 最终结果:统计次数
[
6
,
4
]
[6,4]
[6,4]
+
+
+ 关联组合索引
[
0
,
1
]
[0,1]
[0,1]
样例4
输入
3 5
Test log one
Test log two
Test log three
test
log
one
two
three
输出
3,3,1,1,1,0,1
说明 关键词统计:
t
e
s
t
test
test 出现
3
3
3 次,
l
o
g
log
log 出现
3
3
3 次,
o
n
e
one
one 出现
1
1
1 次,
t
w
o
two
two 出现
1
1
1 次,
t
h
r
e
e
three
three 出现
1
1
1 次 关联组合:(
t
e
s
t
,
l
o
g
test, log
test,log)在第
1
1
1、
2
2
2、
3
3
3 条日志中都同时出现,共现
3
3
3 次
→
→
→ 输出
[
0
,
1
]
[0,1]
[0,1] 其他关键词组合未达到
2
2
2 次共现标准 最终结果:统计次数
[
3
,
3
,
1
,
1
,
1
]
[3,3,1,1,1]
[3,3,1,1,1]
+
+
+ 关联组合索引
[
0
,
1
]
[0,1]
[0,1]题解
题解
思路:模拟
C++
#include<bits/stdc++.h>
#include <cctype>
#include <cstdio>
#include <vector>
using namespace std;
string toLower(string s) {
transform(s.begin(), s.end(), s.begin(),[](unsigned char c) {
return tolower(c);
});
return s;
}
bool isDelim(char c) {
return isspace(static_cast<unsigned char>(c)) || c == ',' || c == '.' ||
c == '!' || c == '?' || c == ';' || c == ':';
}
// 对日志进行分词
vector<string> tokenize(const string& log) {
vector<string> words;
string cur;
for (char c : log) {
if (isDelim(c)) {
if (!cur.empty()) {
words.push_back(toLower(cur));
cur.clear();
}
} else {
cur += c;
}
}
if (!cur.empty()) words.push_back(toLower(cur));
return words;
}
vector<int> totalKeyWord(vector<string>& logs, vector<string>& keywords) {
int n = logs.size();
int m = keywords.size();
vector<int> keywordCount(m, 0);
// 映射关键字(统一转换为小写)到索引
map<string, int> keyWordIndex;
for (int i = 0; i < keywords.size(); i++) {
keyWordIndex[keywords[i]] = i;
}
vector<vector<bool>> isOccur(n, vector<bool>(m, false));
for (int i = 0; i < n; i++) {
vector<string> words = tokenize(logs[i]);
for (auto& word : words) {
// 统一转换小写
string tmp = toLower(word);
if (keyWordIndex.find(tmp) != keyWordIndex.end()) {
int pos = keyWordIndex[tmp];
keywordCount[pos]++;
isOccur[i][pos] = true;
}
}
}
vector<int> ans;
for (int i = 0; i < m; i++) {
ans.push_back(keywordCount[i]);
}
// 找出经常关联
for (int i = 0; i < m; i++) {
for (int j = i + 1; j < m; j++) {
// 同时出现次数
int count = 0;
for (int k = 0; k < n; k++) {
if (!isOccur[k][i] || !isOccur[k][j]) {
continue;
}
count++;
if (count >= 2) {
break;
}
}
if (count >= 2) {
ans.push_back(i);
ans.push_back(j);
}
}
}
return ans;
}
int main() {
int n, m;
cin >> n >> m;
vector<string> logs(n);
vector<string> keywords(m);
cin.ignore();
for (int i = 0; i < n; i++) {
getline(cin, logs[i]);
}
for (int i = 0; i < m; i++) {
getline(cin, keywords[i]);
}
vector<int> ans = totalKeyWord(logs, keywords);
// 输出结果
for (int i = 0; i < ans.size(); i++) {
if (i > 0) {
cout << ",";
}
cout << ans[i];
}
return 0;
}
Java
import java.io.*;
import java.util.*;
public class Main {
static String toLower(String s) {
return s.toLowerCase();
}
static boolean isDelim(char c) {
return Character.isWhitespace(c)
|| c == ','
|| c == '.'
|| c == '!'
|| c == '?'
|| c == ';'
|| c == ':';
}
// 对日志进行分词
static List<String> tokenize(String log) {
List<String> words = new ArrayList<>();
StringBuilder cur = new StringBuilder();
for (char c : log.toCharArray()) {
if (isDelim(c)) {
if (cur.length() > 0) {
words.add(toLower(cur.toString()));
cur.setLength(0);
}
} else {
cur.append(c);
}
}
if (cur.length() > 0) {
words.add(toLower(cur.toString()));
}
return words;
}
static List<Integer> totalKeyWord(List<String> logs, List<String> keywords) {
int n = logs.size();
int m = keywords.size();
int[] keywordCount = new int[m];
// 映射关键字(统一转换为小写)到索引
Map<String, Integer> keyWordIndex = new HashMap<>();
for (int i = 0; i < m; i++) {
keyWordIndex.put(keywords.get(i), i);
}
boolean[][] isOccur = new boolean[n][m];
for (int i = 0; i < n; i++) {
List<String> words = tokenize(logs.get(i));
for (String word : words) {
String tmp = toLower(word);
if (keyWordIndex.containsKey(tmp)) {
int pos = keyWordIndex.get(tmp);
keywordCount[pos]++;
isOccur[i][pos] = true;
}
}
}
List<Integer> ans = new ArrayList<>();
for (int x : keywordCount) {
ans.add(x);
}
// 找出经常关联
for (int i = 0; i < m; i++) {
for (int j = i + 1; j < m; j++) {
int count = 0;
for (int k = 0; k < n; k++) {
if (!isOccur[k][i] || !isOccur[k][j]) {
continue;
}
count++;
if (count >= 2) {
break;
}
}
if (count >= 2) {
ans.add(i);
ans.add(j);
}
}
}
return ans;
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] first = br.readLine().trim().split("\\\\s+");
int n = Integer.parseInt(first[0]);
int m = Integer.parseInt(first[1]);
List<String> logs = new ArrayList<>();
for (int i = 0; i < n; i++) {
logs.add(br.readLine());
}
List<String> keywords = new ArrayList<>();
for (int i = 0; i < m; i++) {
keywords.add(br.readLine());
}
List<Integer> ans = totalKeyWord(logs, keywords);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ans.size(); i++) {
if (i > 0) {
sb.append(",");
}
sb.append(ans.get(i));
}
System.out.print(sb);
}
}
Python
def to_lower(s):
return s.lower()
def is_delim(c):
return c.isspace() or c in ",.!?;:"
# 对日志进行分词
def tokenize(log):
words = []
cur = []
for c in log:
if is_delim(c):
if cur:
words.append("".join(cur).lower())
cur = []
else:
cur.append(c)
if cur:
words.append("".join(cur).lower())
return words
def total_key_word(logs, keywords):
n = len(logs)
m = len(keywords)
keyword_count = [0] * m
# 映射关键字(统一转换为小写)到索引
keyword_index = {}
for i, kw in enumerate(keywords):
keyword_index[kw] = i
is_occur = [[False] * m for _ in range(n)]
for i in range(n):
words = tokenize(logs[i])
for word in words:
tmp = word.lower()
if tmp in keyword_index:
pos = keyword_index[tmp]
keyword_count[pos] += 1
is_occur[i][pos] = True
ans = keyword_count[:]
# 找出经常关联
for i in range(m):
for j in range(i + 1, m):
cnt = 0
for k in range(n):
if not is_occur[k][i] or not is_occur[k][j]:
continue
cnt += 1
if cnt >= 2:
break
if cnt >= 2:
ans.append(i)
ans.append(j)
return ans
n, m = map(int, input().split())
logs = [input() for _ in range(n)]
keywords = [input() for _ in range(m)]
ans = total_key_word(logs, keywords)
print(",".join(map(str, ans)))
JavaScript
const readline = require("readline");
function toLower(s) {
return s.toLowerCase();
}
function isDelim(c) {
return /\\s/.test(c) || ",.!?;:".includes(c);
}
// 对日志进行分词
function tokenize(log) {
const words = [];
let cur = "";
for (const c of log) {
if (isDelim(c)) {
if (cur.length > 0) {
words.push(cur.toLowerCase());
cur = "";
}
} else {
cur += c;
}
}
if (cur.length > 0) {
words.push(cur.toLowerCase());
}
return words;
}
function totalKeyWord(logs, keywords) {
const n = logs.length;
const m = keywords.length;
const keywordCount = Array(m).fill(0);
// 映射关键字(统一转换为小写)到索引
const keywordIndex = new Map();
for (let i = 0; i < m; i++) {
keywordIndex.set(keywords[i], i);
}
const isOccur = Array.from(
{ length: n },
() => Array(m).fill(false)
);
for (let i = 0; i < n; i++) {
const words = tokenize(logs[i]);
for (const word of words) {
const tmp = word.toLowerCase();
if (keywordIndex.has(tmp)) {
const pos = keywordIndex.get(tmp);
keywordCount[pos]++;
isOccur[i][pos] = true;
}
}
}
const ans = […keywordCount];
// 找出经常关联
for (let i = 0; i < m; i++) {
for (let j = i + 1; j < m; j++) {
let cnt = 0;
for (let k = 0; k < n; k++) {
if (!isOccur[k][i] || !isOccur[k][j]) {
continue;
}
cnt++;
if (cnt >= 2) {
break;
}
}
if (cnt >= 2) {
ans.push(i);
ans.push(j);
}
}
}
return ans;
}
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const lines = [];
rl.on("line", line => {
lines.push(line);
});
rl.on("close", () => {
let idx = 0;
const [n, m] = lines[idx++].trim().split(/\\s+/).map(Number);
const logs = [];
for (let i = 0; i < n; i++) {
logs.push(lines[idx++]);
}
const keywords = [];
for (let i = 0; i < m; i++) {
keywords.push(lines[idx++]);
}
const ans = totalKeyWord(logs, keywords);
console.log(ans.join(","));
});
Go
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func toLower(s string) string {
return strings.ToLower(s)
}
func isDelim(c byte) bool {
return c == ' ' ||
c == '\\t' ||
c == '\\n' ||
c == '\\r' ||
c == ',' ||
c == '.' ||
c == '!' ||
c == '?' ||
c == ';' ||
c == ':'
}
// 对日志进行分词
func tokenize(log string) []string {
words := make([]string, 0)
cur := strings.Builder{}
for i := 0; i < len(log); i++ {
c := log[i]
if isDelim(c) {
if cur.Len() > 0 {
words = append(words, strings.ToLower(cur.String()))
cur.Reset()
}
} else {
cur.WriteByte(c)
}
}
if cur.Len() > 0 {
words = append(words, strings.ToLower(cur.String()))
}
return words
}
func totalKeyWord(logs []string, keywords []string) []int {
n := len(logs)
m := len(keywords)
keywordCount := make([]int, m)
// 映射关键字(统一转换为小写)到索引
keyWordIndex := make(map[string]int)
for i := 0; i < m; i++ {
keyWordIndex[keywords[i]] = i
}
isOccur := make([][]bool, n)
for i := 0; i < n; i++ {
isOccur[i] = make([]bool, m)
}
for i := 0; i < n; i++ {
words := tokenize(logs[i])
for _, word := range words {
tmp := strings.ToLower(word)
if pos, ok := keyWordIndex[tmp]; ok {
keywordCount[pos]++
isOccur[i][pos] = true
}
}
}
ans := make([]int, 0)
ans = append(ans, keywordCount…)
// 找出经常关联
for i := 0; i < m; i++ {
for j := i + 1; j < m; j++ {
cnt := 0
for k := 0; k < n; k++ {
if !isOccur[k][i] || !isOccur[k][j] {
continue
}
cnt++
if cnt >= 2 {
break
}
}
if cnt >= 2 {
ans = append(ans, i, j)
}
}
}
return ans
}
func main() {
reader := bufio.NewReader(os.Stdin)
var n, m int
fmt.Fscan(reader, &n, &m)
reader.ReadString('\\n')
logs := make([]string, n)
for i := 0; i < n; i++ {
line, _ := reader.ReadString('\\n')
logs[i] = strings.TrimRight(line, "n")
}
keywords := make([]string, m)
for i := 0; i < m; i++ {
line, _ := reader.ReadString('\\n')
keywords[i] = strings.TrimRight(line, "\\n")
}
ans := totalKeyWord(logs, keywords)
for i := 0; i < len(ans); i++ {
if i > 0 {
fmt.Print(",")
}
fmt.Print(ans[i])
}
}
C语言
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#define MAX_LOGS 1000
#define MAX_KEYWORDS 100
#define MAX_LEN 1005
void toLower(char *s) {
for (int i = 0; s[i]; i++) {
s[i] = tolower((unsigned char)s[i]);
}
}
bool isDelim(char c) {
return isspace((unsigned char)c)
|| c == ','
|| c == '.'
|| c == '!'
|| c == '?'
|| c == ';'
|| c == ':';
}
// 对日志进行分词
int tokenize(char *log, char words[][MAX_LEN]) {
int cnt = 0;
char cur[MAX_LEN];
int len = 0;
for (int i = 0; log[i]; i++) {
char c = log[i];
if (isDelim(c)) {
if (len > 0) {
cur[len] = '\\0';
toLower(cur);
strcpy(words[cnt++], cur);
len = 0;
}
} else {
cur[len++] = c;
}
}
if (len > 0) {
cur[len] = '\\0';
toLower(cur);
strcpy(words[cnt++], cur);
}
return cnt;
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
getchar();
char logs[MAX_LOGS][MAX_LEN];
char keywords[MAX_KEYWORDS][MAX_LEN];
for (int i = 0; i < n; i++) {
fgets(logs[i], MAX_LEN, stdin);
logs[i][strcspn(logs[i], "\\n")] = '\\0';
}
for (int i = 0; i < m; i++) {
fgets(keywords[i], MAX_LEN, stdin);
keywords[i][strcspn(keywords[i], "\\n")] = '\\0';
}
int keywordCount[MAX_KEYWORDS] = {0};
bool isOccur[MAX_LOGS][MAX_KEYWORDS] = {false};
for (int i = 0; i < n; i++) {
char words[2000][MAX_LEN];
int wordCnt = tokenize(logs[i], words);
for (int j = 0; j < wordCnt; j++) {
for (int k = 0; k < m; k++) {
if (strcmp(words[j], keywords[k]) == 0) {
keywordCount[k]++;
isOccur[i][k] = true;
}
}
}
}
bool first = true;
for (int i = 0; i < m; i++) {
if (!first) printf(",");
first = false;
printf("%d", keywordCount[i]);
}
// 找出经常关联
for (int i = 0; i < m; i++) {
for (int j = i + 1; j < m; j++) {
int cnt = 0;
for (int k = 0; k < n; k++) {
if (!isOccur[k][i] || !isOccur[k][j]) {
continue;
}
cnt++;
if (cnt >= 2) {
break;
}
}
if (cnt >= 2) {
printf(",%d,%d", i, j);
}
}
}
return 0;
}
