问题陈述:Sherlock and the Valid String
此代码通过了所有正确性测试(15/20),但是由于时间限制,某些测试失败。
有什么好的方法可以使代码更快?如何避免app.post("/bioform",function(req,res){
let email = req.body.email;
if (!!email) {
// Register.ejs request
// Your registration process can be done here
}else{
// home.ejs request
// Your login process can be done here
}
// var userName = req.body.username;
// res.render("bioform",{userName:userName});
});
循环?
for
答案 0 :(得分:3)
我不会直截了当地告诉您出了什么问题,但我将为您提供一个概念框架,您可以通过该框架来分析代码。
考虑一下您在输入字符串中每个字母执行的步骤数。
如果执行固定数量的步骤,则将得到线性缩放比例。假设您每个字母执行三个步骤。如果有 n 个字母并且您执行 3n 个操作,则表示状态良好。
但是,如果您对每个字母执行 n 个操作,则可以使用n²或3n²进行二次缩放或总计操作。 (前面的常量并不重要。重要的是指数。)假设您有1,000个字母。 3n 缩放将意味着3千次操作。 3n²缩放将意味着3 一百万。
二次方基本上意味着“不缩放”。当输入变大时,二次算法会爆炸,而不是与输入长度成比例地缩放。它们可以正常工作,但在压力下会崩溃。黑客排名很可能会在您的算法中抛出非常长的输入字符串,以检测二次爆炸。
我在上面谈到了 n 。在Java语言中, n 是s.length()
。您可以在执行s.length() * s.length()
操作的代码中发现二次步骤吗?
是的,在第1步中,我在
s
上进行了两次迭代,以计算每个字符的频率。
是的。好。现在,如何单步执行步骤1?
考虑如何在纸上做。您不会一遍又一遍又一遍又一遍地扫描字符串,对吗?您只需要查看每个字母一次,就可以对所有字母进行连续计数。您可能会在一张桌子上放上字母和提示标记,例如:
A ||||
B
C |
D ||
E |||||||
F
...
执行相同的代码,它将n²削减为 n 。
答案 1 :(得分:1)
除了@JohnKugelman答案,这是您可以做的。
首先,您要遍历您的字符串两次(带内循环)以计算出现的次数O(n ^ 2)。您已经找到了一个O(n)解决方案
Map<Character, Integer> occurences = new HashMap<>();
s.chars()
.forEach(e-> occurences.put((char)e, occurences.getOrDefault((char)e, 0) + 1));
现在我们需要找到一个简单的迭代来找出答案。
这是我们对"YES"
案例的了解。
所以我们需要做的是浏览地图的值并计算出现的次数。
首先,让我们获得迭代器
Iterator<Map.Entry<Character, Integer>> iterator = occurences
.entrySet()
.iterator();
然后选择第一个数字作为“基准”,并为第一个不同的值定义一个变量和一个计数
int benchmark = iterator.next().getValue();
int benchmarkCount = 1;
int firstDifferent = -1;
int differentCount = 0;
遍历数字
while(iterator.hasNext()) {
int next = iterator.next().getValue();
if (next == benchmark) { // if the next number is same
benchmarkCount++; // just update our count
} else { // if it is different
// if we haven't found a different one yet or it is the same different value from earlier
if (firstDifferent == -1 || firstDifferent == next) {
firstDifferent = next;
differentCount++;
}
}
}
现在我们要做的就是分析我们的数字
int size = occurences.size();
if (benchmarkCount == size) return "YES"; // if all of the numbers are the same
if (benchmarkCount == size - 1) { // if we hit only single different
// either the diffent number is 1 or it is greater than our benchmark by value of 1
if (firstDifferent == 1 || firstDifferent - benchmark == 1) {
return "YES";
}
}
// same case with above
if (differentCount == size - 1) {
if (benchmark == 1 || benchmark - firstDifferent == 1) {
return "YES";
}
}
完整解决方案
static String isValid(String s) {
Map<Character, Integer> occurences = new HashMap<>();
s.chars().forEach(e-> occurences.put((char)e, occurences.getOrDefault((char)e, 0) + 1));
Iterator<Map.Entry<Character, Integer>> iterator = occurences
.entrySet()
.iterator();
int benchmark = iterator.next().getValue();
int benchmarkCount = 1;
int firstDifferent = -1;
int differentCount = 0;
while(iterator.hasNext()) {
int next = iterator.next().getValue();
if (next == benchmark) {
benchmarkCount++;
} else {
if (firstDifferent == -1 || firstDifferent == next) {
firstDifferent = next;
differentCount++;
}
}
}
int size = occurences.size();
if (benchmarkCount == size) return "YES";
if (benchmarkCount == size - 1) {
if (firstDifferent == 1 || firstDifferent - benchmark == 1) {
return "YES";
}
}
if (differentCount == size - 1) {
if (benchmark == 1 || benchmark - firstDifferent== 1) {
return "YES";
}
}
return "NO";
}
答案 2 :(得分:0)
我发现其他解决方案太复杂了。使用不同字符的数量(下面的counts.length
)和它们的最小频率(下面的min
),我们知道字符串长度至少为counts.length * min
。
当单个字符出现的次数多于min
时,我们的字符串长一。
如果有更多这样的字符,则字符串的长度将超过counts.length * min + 1
。如果任何字符出现的次数甚至超过min + 1
,则字符串的长度也超过counts.length * min + 1
。
正如Bunyamin Coskuner指出的那样,我的解决方案未找到类似“ aabbc”的案例。这个可以工作,但不再像想要的那么简单:
static String isValid(String s) {
if (s.isEmpty()) return "YES";
final int[] counts = s.chars()
.mapToObj(c -> c)
.collect(Collectors.groupingBy(c -> c, Collectors.counting()))
.values()
.stream()
.mapToInt(n -> n.intValue())
.toArray();
final int min = Arrays.stream(counts).min().getAsInt();
// Accounts for strings like "aabb" and "aabbb".
if (s.length() <= counts.length * min + 1) return "YES";
// Here, strings can be only valid when the minimum is one, like for "aabbc".
if (min != 1) return "NO";
final int minButOne = Arrays.stream(counts).filter(n -> n>1).min().getAsInt();
return s.length() == (counts.length - 1) * minButOne + 1 ? "YES" : "NO";
}