一、Problem
我们来定义一个函数 f(s),其中传入参数 s 是一个非空字符串;该函数的功能是统计 s 中(按字典序比较)最小字母的出现频次。
例如,若 s = “dcce”,那么 f(s) = 2,因为最小的字母是 “c”,它出现了 2 次。
现在,给你两个字符串数组待查表 queries 和词汇表 words,请你返回一个整数数组 answer 作为答案,其中每个 answer[i] 是满足 f(queries[i]) < f(W) 的词的数目,W 是词汇表 words 中的词。
输入:queries = ["cbd"], words = ["zaaaz"]
输出:[1]
解释:查询 f("cbd") = 1,而 f("zaaaz") = 3 所以 f("cbd") < f("zaaaz")。
提示:
1 <= queries.length <= 2000
1 <= words.length <= 2000
1 <= queries[i].length, words[i].length <= 10
queries[i][j], words[i][j] 都是小写英文字母
二、Solution
方法一:暴力
没啥可说的…
class Solution {
int f(char[] w) {
int[] mp = new int[258];
for (char c : w)
mp[c]++;
Arrays.sort(w);
return mp[w[0]];
}
public int[] numSmallerByFrequency(String[] qs, String[] ws) {
List<Integer> l = new LinkedList<>();
for (String w : ws)
l.add(f(w.toCharArray()));
List<Integer> ans = new ArrayList<>();
for (String q : qs) {
int cnt = f(q.toCharArray()), b = 0;
for (int c : l) if (c > cnt) {
b++;
}
ans.add(b);
}
int[] a = new int[ans.size()];
for (int i = 0; i <a.length; i++)
a[i] = ans.get(i);
return a;
}
}
可优化的地方有二:
- 方法 ,里利用一个遍历 min 记录字典序最小字符。
- 利用 fori 来遍历 qs,然后嵌套遍历 ws,省去开一个 List 来装载结果。
复杂度分析
- 时间复杂度: ,qs 表示查询的组数
- 空间复杂度: ,
方法二:二分优化
由于是在 words[] 中找的是比 f(query[i]) 小的所有字符串的数量,所以可用 f 先求出 words 中所有的值到数组 a 中,然后排序,遍历 query 的时候用二分法在 a 中统计所有大于 query[i] 的数量。
class Solution {
int f(String s) {
int min = 'z'+5, cnt = 0;
for (char c : s.toCharArray()) {
if (c < min) {
min = c;
cnt = 0;
} else if (c == min){
cnt++;
}
}
return cnt;
}
public int[] numSmallerByFrequency(String[] qs, String[] ws) {
int m = ws.length, a[] = new int[m];
for (int i = 0; i < m; i++)
a[i] = f(ws[i]);
Arrays.sort(a);
int n = qs.length, ans[] = new int[n];
for (int i = 0; i < n; i++) {
int tar = f(qs[i]), l = 0, r = m-1;
while (l < r) {
int mid = l + r >>> 1;
if (a[mid] > tar) {
r = mid;
} else {
l = mid + 1;
}
}
ans[i] = tar >= a[l] ? 0 : m - l;
}
return ans;
}
}
复杂度分析
- 时间复杂度: ,N = max(m, n)
- 空间复杂度: ,