有什么好的方法可以使代码更快?

时间:2020-04-24 22:46:43

标签: java performance optimization

问题陈述: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

3 个答案:

答案 0 :(得分:3)

我不会直截了当地告诉您出了什么问题,但我将为您提供一个概念框架,您可以通过该框架来分析代码。

考虑一下您在输入字符串中每个字母执行的步骤数。

  • 如果执行固定数量的步骤,则将得到线性缩放比例。假设您每个字母执行三个步骤。如果有 n 个字母并且您执行 3n 个操作,则表示状态良好。

  • 但是,如果您对每个字母执行 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

答案 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"案例的了解。

  • 所有字母的频率相同,例如:aabbccddeeff
  • 所有字母具有相同的频率,但单个字母出现次数增加1次。例如:aabbccddd
  • 所有字母具有相同的频率,但单个字母出现1次。例如:aaaabbbbcccce

所以我们需要做的是浏览地图的值并计算出现的次数。

首先,让我们获得迭代器

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";
}