找到重复数字序列的索引中点的最有效算法是什么?

时间:2019-07-12 17:26:30

标签: python c++11 vector

a=[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 -1, -1, -1, -1,-1, 0, 0, 0, 0, 0]

我希望能够获得重复点索引的中点,即

output_vector = [2, 8,  13, 19]

即output_vector [0]是第一个序列0, 0, 0, 0, 0

的中点的索引

output_vector [1]是第二个重复序列1, 1, 1, 1, 1, 1, 1

的中点

output_vector [2]是第二个重复序列-1, -1, -1, -1,-1

的中点

4 个答案:

答案 0 :(得分:2)

一种方法是使用itertools.groupby查找组并计算其中点:

from itertools import groupby

a = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1,-1, 0, 0, 0, 0, 0]

groups = [list(g) for _, g in groupby(a)]    
output_vector = [sum(1 for x in groups[:i] for _ in x) + len(x) // 2 for i, x in enumerate(groups)]
# [2, 8, 14, 19]

答案 1 :(得分:2)

itertools方法可能更好,更干净。尽管如此,这是一种使用mathstatistics的方法,它要查找每组数字的起始索引和终止索引的中位数。

import math
import statistics as stat

a = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0]

lastNum = None
startIdx = 0
midpts = []
for idx, x in enumerate(a):
    if lastNum is not None and lastNum != x or idx == len(a) - 1:
        midpts.append(math.floor(stat.median([startIdx, idx])))
        startIdx = idx
    lastNum = x

print(midpts)
# [2, 8, 14, 19]

答案 2 :(得分:2)

另一个基于itertools的解决方案,但效率更高。

from itertools import groupby

a = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1,-1, 0, 0, 0, 0, 0]

output = []
psum = 0 
for glen in (sum(1 for i in g) for k, g in groupby(a)):
    output.append(psum + glen // 2)
    psum += glen

print(output)

答案 3 :(得分:1)

基于C ++的@Matt M答案的实现

  template<typename T>
    std::vector<size_t> getPeaks(std::vector<T>& input_vector) {
        std::vector<size_t> output;
        T lastNum = 10000;
        size_t startIdx = 0;
        for (size_t i = 0; i < input_vector.size(); ++i) {
            if ((lastNum != 10000 and lastNum != input_vector[i]) || (i == input_vector.size() - 1)) {
                auto medianIdx = findMedian(startIdx, i);
                output.emplace_back(medianIdx);
                startIdx = i;

            }
            lastNum = input_vector[i];
        }
        return output;

}

 size_t findMedian(size_t start, size_t end) {
    return start + (end - start) / 2;
}