寻找数值下降速度超过二次时间的最长区间

huangapple go评论54阅读模式
英文:

Finding the longest interval with a decrease in value faster than quadratic time

问题

我有一组某个度量标准的数值,例如:

# 0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16
[50, 52, 58, 54, 57, 51, 55, 60, 62, 65, 68, 72, 62, 61, 59, 63, 72]

我需要找出数值下降最多的最长区间。对于上面的列表,这样的区间从索引 7 到 14(长度为 8)。对此,有一个O(n^2)的解决方案:

def get_longest_len(values: list[int]) -> int:
    longest = 0

    for i in range(len(values)-1):
        for j in range(len(values)-1, i, -1):
            if values[i] > values[j] and j - i > longest:
                longest = j - i
                break
    return longest + 1

有没有办法提高它的时间复杂度?

英文:

I have a list of values for some metric, e.g.:

# 0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16
[50, 52, 58, 54, 57, 51, 55, 60, 62, 65, 68, 72, 62, 61, 59, 63, 72]

I need to find the longest interval over which the value has decreased. For the above list such interval is from index 7 to 14 (and it's length is 8). An O(n²) solution to this is simple:

def get_longest_len(values: list[int]) -> int:
    longest = 0

    for i in range(len(values)-1):
        for j in range(len(values)-1, i, -1):
            if values[i] > values[j] and j - i > longest:
                longest = j - i
                break
    return longest + 1

Is there any way to improve it's time complexity?

答案1

得分: 2

以下是代码的翻译部分:

from itertools import accumulate
from bisect import bisect

def get_longest_len(values: list[int]) -> int:
    maxi = list(accumulate(values, max))
    return max(
        i - bisect(maxi, value) + 1
        for i, value in enumerate(values)
    )

cases = 100
correct = 0
for _ in range(cases):
    values = [i + randint(-10, 10) for i in range(1000)]
    for _ in range(5):
        i, j = sample(range(1000), 2)
        values[i], values[j] = values[j], values[i]
    expect = get_longest_len0(values)
    result = get_longest_len(values)
    correct += result == expect
    print(result == expect, expect, result)
print(correct, 'out of', cases, 'correct')

希望这对你有帮助。

英文:

O(n log n):

from itertools import accumulate
from bisect import bisect

def get_longest_len(values: list[int]) -> int:
    maxi = list(accumulate(values, max))
    return max(
        i - bisect(maxi, value) + 1
        for i, value in enumerate(values)
    )

First I compute the prefix maxima. For your example:

#          0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16
values = [50, 52, 58, 54, 57, 51, 55, 60, 62, 65, 68, 72, 62, 61, 59, 63, 72]
maxi   = [50, 52, 58, 58, 58, 58, 58, 60, 62, 65, 68, 72, 72, 72, 72, 72, 72]

Then for each value, I can use binary search in these maxima to find the earliest larger value. For example the 59 at index 14 in values: We find that the earliest number in maxi larger than 59 is the 60 at index 7.

Correctness testing with 100 lists of 1000 randomized ascending values (the two numbers for each test case are your result and mine, and the boolean says whether they match):

True 461 461
True 360 360
True 909 909
    ...
True 576 576
True 312 312
True 810 810
100 out of 100 correct

Code:

from itertools import accumulate
from bisect import bisect
from random import randint, sample

def get_longest_len0(values: list[int]) -> int:
    longest = 0

    for i in range(len(values)-1):
        for j in range(len(values)-1, i, -1):
            if values[i] > values[j] and j - i > longest:
                longest = j - i
                break
    return longest + 1

def get_longest_len(values: list[int]) -> int:
    maxi = list(accumulate(values, max))
    return max(
        i - bisect(maxi, value) + 1
        for i, value in enumerate(values)
    )

cases = 100
correct = 0
for _ in range(cases):
    values = [i + randint(-10, 10) for i in range(1000)]
    for _ in range(5):
        i, j = sample(range(1000), 2)
        values[i], values[j] = values[j], values[i]
    expect = get_longest_len0(values)
    result = get_longest_len(values)
    correct += result == expect
    print(result == expect, expect, result)
print(correct, 'out of', cases, 'correct')

Attempt This Online!

huangapple
  • 本文由 发表于 2023年2月16日 02:27:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/75464017.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定