백만 개의 문자열이 주어지면 반복되는 세 자리 숫자를 모두 반환하십시오.


137

몇 달 전에 뉴욕의 헤지 펀드 회사와 인터뷰를했지만 불행히도 데이터 / 소프트웨어 엔지니어로서 인턴쉽을받지 못했습니다. (또한 파이썬으로 솔루션을 요청했습니다.)

나는 첫 인터뷰 문제에 거의 망 쳤어.

질문 : 백만 개의 문자열 (예 : Pi)이 주어지면 반복되는 3 자리 숫자와 1보다 큰 반복 횟수를 모두 반환하는 함수 / 프로그램을 작성하십시오.

예를 들어 문자열이 123412345123456다음과 같으면 함수 / 프로그램은 다음을 반환합니다.

123 - 3 times
234 - 3 times
345 - 2 times

그들은 인터뷰에 실패한 후에 해결책을주지 않았지만 가능한 모든 결과가 다음과 같기 때문에 해결책의 시간 복잡성이 1000이라고 일정하다고 말했습니다.

000-> 999

나는 그것에 대해 생각하고 있기 때문에 일정한 시간 알고리즘을 생각해내는 것이 불가능하다고 생각합니다. 그렇습니까?


68
솔루션이 1000의 상수라고 생각하면 3 자리 숫자를 모두 작성한 다음 정규 표현식을 검색했다고 생각합니다. 사람들이 실제로 쓰거나 보지 않은 작업이 "무료"라고 생각하는 것은 매우 흔한 일입니다. 나는 이것이 문자열의 길이와 선형 일 것이라고 확신합니다.
mypetlion

54
입력 크기가 일정하면 Nitpickingly, 모든 알고리즘은 일정 시간; - 인
파올로 Ebermann

34
1000의 상수는 무엇 입니까? (추가? 코끼리?)
ilkkachu

31
문자열 길이가 일정하고 (1M) 부분 문자열 / 숫자 길이가 일정하면 (3) 기술적으로 모든 솔루션은 일정합니다…
Kevin

8
They did not give me the solution after I failed the interview, but they did tell me that the time complexity for the solution was constant of 1000 since all the possible outcomes are between: 000 --> 999 이것은 실제 테스트 일 가능성이 높습니다. 이것이 불가능한 이유를 증명하고 올바른 최소 시간 복잡성을 보여줄 수 있는지 확인하십시오.
James

답변:


168

당신은 당신이 아마 가볍게 내려서 하지 quants 기본 알고리즘을 이해하지 못하는 헤지 펀드에 대한 작동 할 :-)

이 경우처럼 모든 요소를 ​​한 번 이상 방문해야하는 경우 임의 크기의 데이터 구조를 처리 할 수있는 방법 이 없습니다O(1) . 최고의 당신이 희망 할 수있다 O(n)이 경우에 n문자열의 길이입니다.

제쳐두고, 공칭 비록 O(n)알고리즘 O(1)있으므로, 고정 된 기술적 입력 크기를 들어, 여기에 올바른일지도 모른다. 그러나 이것이 일반적으로 사람들이 복잡성 분석을 사용하는 방식은 아닙니다.

여러 가지 방법으로 그들에게 깊은 인상을 줄 수 있었던 것 같습니다.

먼저 위에서 언급 한 "의심스러운"추론을 사용하지 않는 한에 할 수 없음 을 알리십시오 O(1).

둘째, 다음과 같은 Pythonic 코드를 제공하여 엘리트 기술을 보여줍니다.

inpStr = '123412345123456'

# O(1) array creation.
freq = [0] * 1000

# O(n) string processing.
for val in [int(inpStr[pos:pos+3]) for pos in range(len(inpStr) - 2)]:
    freq[val] += 1

# O(1) output of relevant array values.
print ([(num, freq[num]) for num in range(1000) if freq[num] > 1])

이 결과는 다음과 같습니다.

[(123, 3), (234, 3), (345, 2)]

물론 출력 형식을 원하는대로 수정할 수 있습니다.

마지막으로, 위의 코드는 0.5 초 안에 100 만 자릿수 문자열에 대한 결과를 제공하기 때문에 솔루션에 아무런 문제가 거의 없다고O(n) 말합니다. 10,000,000 자 문자열은 3.5 초가 걸리고 100,000,000 자 문자열은 36 초가 걸리기 때문에 선형 적으로도 확장되는 것으로 보입니다.

그리고 그것들 그보다 더 필요 하다면 , 속도를 크게 높일 수있는 이런 종류의 것들을 병렬화하는 방법이 있습니다.

물론 GIL로 인해 단일 파이썬 인터프리터 내에는 아니지만 문자열을 다음과 같이 나눌 수 있습니다 ( vv경계 영역을 올바르게 처리하려면 겹침이 표시 되어야 함).

    vv
123412  vv
    123451
        5123456

이를 분리하여 작업자를 분리하고 나중에 결과를 결합 할 수 있습니다.

입력 분할과 출력 결합은 작은 문자열 (및 수백만 자릿수의 문자열)로 절약 할 수 있지만 훨씬 더 큰 데이터 세트의 경우 큰 차이가있을 수 있습니다. 물론 "측정, 추측하지 말아"라는 나의 평범한 만트라가 여기에 적용됩니다.


이 만트라는 파이썬을 우회하고 더 빠른 다른 언어를 사용하는 것과 같은 다른 가능성 에도 적용됩니다 .

예를 들어, 다음의 코드 C는 이전 파이썬 코드와 동일한 하드웨어에서 실행하는 처리 0.6 초 만 자리 파이썬 코드 처리 시간으로 대략 동일한 양의 하나 백만. 다시 말해, 훨씬 빠릅니다.

#include <stdio.h>
#include <string.h>

int main(void) {
    static char inpStr[100000000+1];
    static int freq[1000];

    // Set up test data.

    memset(inpStr, '1', sizeof(inpStr));
    inpStr[sizeof(inpStr)-1] = '\0';

    // Need at least three digits to do anything useful.

    if (strlen(inpStr) <= 2) return 0;

    // Get initial feed from first two digits, process others.

    int val = (inpStr[0] - '0') * 10 + inpStr[1] - '0';
    char *inpPtr = &(inpStr[2]);
    while (*inpPtr != '\0') {
        // Remove hundreds, add next digit as units, adjust table.

        val = (val % 100) * 10 + *inpPtr++ - '0';
        freq[val]++;
    }

    // Output (relevant part of) table.

    for (int i = 0; i < 1000; ++i)
        if (freq[i] > 1)
            printf("%3d -> %d\n", i, freq[i]);

    return 0;
}

19
이 "고정 입력 크기"는 실제로 면접관이나 면담자가 얻지 못한 농담처럼 들립니다. 모든 알고리즘하게 O(1)되는 n고정 또는 묶여있다.
Eric Duminil '12

5
그것들이 그보다 더 필요하다면, 적어도 특정 알고리즘에 대해 파이썬을 사용해서는 안됩니다.
Sebastian Redl

3
@ezzzCash 병렬 접근을 시도 할 때 문자열이 "깨진"지점에서 겹칠 수 있기 때문입니다. 3 자리 그룹을 찾고 있으므로 -2를 사용하면 두 병렬 그룹을 모두 검사 하여 잠재적으로 유효한 일치 항목을 놓치지 않을 수 있습니다.
code_dredd

5
@ezzzCash 병렬 프로그래밍 지식이 부족하지 않습니다. length의 문자열을 고려하십시오 N. 위치에서 두 부분으로 나눠도 N/2"테두리"에서 string1시작과 끝의 유효한 3 자리 일치를 놓칠 수 있다는 사실을 여전히 고려해야합니다 string2. 따라서, 당신은 사이의 일치를 확인해야 string1[N/2-2]하고 string2[2]아이디어의 등 (0부터 시작하는 인덱스를 사용).
code_dredd

1
긴 자릿수 시퀀스를 사용하면 가장 높은 자릿수를 삭제하고 새 자릿수를 추가 할 수있는 슬라이딩 윈도우를 사용하여 정수로의 변환을 최적화하여 얻을 수 있습니다. (파이썬 오버 헤드는 아마도 이것을 죽일 수 있으므로 C 또는 다른 저수준 구현에만 적용됩니다). val -= 100 * (d[i]-'0');선행 숫자를 삭제하십시오. val = 10*val + d[i+2]-'0'새로운 최소 유효 자릿수 (일반 문자열-> 정수 구문 분석)를 축적합니다. val % 100아마도 무시할 수 없지만 100컴파일 타임 상수 인 경우에만 실제 HW 나누기를 사용하지 않습니다.
Peter Cordes

78

일정한 시간이 불가능합니다. 모든 백만 자릿수는 적어도 한 번 이상 볼 필요가 있으므로 O (n)의 시간 복잡성입니다.이 경우 n = 백만입니다.

간단한 O (n) 솔루션의 경우 가능한 각 3 자리 숫자의 발생 횟수를 나타내는 1000 크기의 배열을 작성하십시오. 한 번에 1 자리 씩 이동하고 첫 번째 인덱스 == 0, 마지막 인덱스 == 999997 및 증분 배열 [3 자리 숫자]을 사용하여 히스토그램 (가능한 3 자리 숫자마다 발생 횟수)을 만듭니다. 그런 다음 개수가 1보다 큰 배열의 내용을 출력하십시오.


26
@ezzzCash-예 사전은 작동하지만 필요하지는 않습니다. 가능한 모든 "키"는 0에서 999까지의 범위로 미리 알려져 있습니다. 오버 헤드의 차이는 3 개의 문자열을 키로 사용하여 키 기반 액세스를 수행하는 데 걸리는 시간과 3을 변환하는 데 걸리는 시간입니다. 숫자 문자열을 색인에 연결 한 다음 색인을 사용하여 배열에 액세스하십시오.
rcgldr

4
숫자 트릭을 원하면 BCD로 이동하여 세 자리를 12 비트로 저장할 수도 있습니다. 하위 4 비트를 마스킹하여 ASCII 숫자를 디코딩하십시오. 그러나 그 x-'0'패턴은 파이썬에서는 유효하지 않으며 C-ism입니다 (문자는 정수입니다).
Yann Vernier

5
@LorenPechtel : 파이썬에서 사전 검색은 정말 빠릅니다. 물론 배열 액세스가 훨씬 빠르기 때문에 처음부터 정수를 다루는 경우 옳습니다. 그러나이 경우 3 길이의 문자열이 있는데, 배열과 함께 사용하려면 먼저 정수로 변환해야합니다. 우리가 처음 기대할 수있는 것과는 달리 사전 검색은 실제로 정수 변환 + 배열 액세스보다 빠릅니다. 이 경우 어레이 솔루션은 실제로 50 % 느려집니다.
Aleksi Torhamo

2
나는 사람이 주장 할 수 추측 입력 번호가있는 경우 그 정확히 항상 그 알고리즘보다 100 만 개 숫자 입니다 O (1) 1 백만의 일정한 팩터.
tobias_k

2
@AleksiTorhamo-목표가 알고리즘의 상대적 구현 속도를 비교하는 것이라면 파이썬이 상당히 느리고 다른 언어에 비해 파이썬 고유의 오버 헤드가있는 것처럼 C 또는 C ++와 같은 전통적인 언어를 선호합니다.
rcgldr

14

아래 답변에 백만이 작습니다. 인터뷰에서 솔루션을 일시 정지없이 실행할 수 있어야한다고 예상하면 다음은 2 초 이내에 작동하며 필요한 결과를 제공합니다.

from collections import Counter

def triple_counter(s):
    c = Counter(s[n-3: n] for n in range(3, len(s)))
    for tri, n in c.most_common():
        if n > 1:
            print('%s - %i times.' % (tri, n))
        else:
            break

if __name__ == '__main__':
    import random

    s = ''.join(random.choice('0123456789') for _ in range(1_000_000))
    triple_counter(s)

면접관이 표준 라이브러리 컬렉션을 사용할 수 있기를 바랍니다.

병렬 실행 버전

자세한 설명과 함께 블로그 게시물 을 작성했습니다 .


그것은 잘 작동하며 가장 빠르고 비 numpy 솔루션 인 것 같습니다.
Eric Duminil

3
@EricDuminil, 주어진 대부분의 솔루션으로 많은 시간이 걸리지 않을 때 여기에서 빠른 타이밍을 걱정할 필요는 없다고 생각합니다. 파이썬 표준 라이브러리를 잘 이해하고 있으며 인터뷰 상황에서 유지 관리 가능한 코드를 작성할 수 있다는 것을 보여주는 것이 좋습니다. (면접관 이 다음 시간을 평가하기 전에 실제 타이밍을 요청해야하는 시간 임계성을 강조 하지 않은 경우 ).
Paddy3118

1
우리는 100 % 동의합니다. 면접관이 실제로 할 수 있다고 생각하면 답변이 전혀 관련이 있는지 확실하지 않습니다 O(1).
Eric Duminil

1
면접관이 시간이 중요하다는 점을 강조한 경우 , 이것이 한계인지 확인하기 위해 프로파일 링 후이 병목 현상을 해결하기 위해 C 모듈을 작성해야 할 때입니다. ac 모듈 사용으로 전환 한 후 파이썬 코드보다 84 배 개선 된 스크립트가 있습니다.
TemporalWolf

@ @ TemporalWolf, 나는 당신이 말한 것을 읽은 다음, 더 빠르고 확장 가능한 또 다른 솔루션은 그것을 병렬 알고리즘으로 변경하여 컴퓨팅 팜 / 클라우드의 많은 프로세스에서 실행될 수 있다고 생각했습니다. 문자열을 n 개의 섹션으로 분할해야합니다. 각 섹션의 마지막 3자를 다음 섹션과 겹칩니다. 그런 다음 각 섹션을 독립적으로 트리플에 대해 스캔하고 트리플을 합산하고 마지막 섹션을 제외한 3 개의 숯 트리플을 두 번 계산했을 때 뺄 수 있습니다. 나는 ... 코드를 가지고 있고, 아마 블로그 게시물로 바뀔 것이다
Paddy3118

13

간단한 O (n) 솔루션은 각 3 자리 숫자를 세는 것입니다.

for nr in range(1000):
    cnt = text.count('%03d' % nr)
    if cnt > 1:
        print '%03d is found %d times' % (nr, cnt)

이것은 백만 자릿수를 1000 번 모두 검색합니다.

한 번만 숫자를 순회 :

counts = [0] * 1000
for idx in range(len(text)-2):
    counts[int(text[idx:idx+3])] += 1

for nr, cnt in enumerate(counts):
    if cnt > 1:
        print '%03d is found %d times' % (nr, cnt)

타이밍은 인덱스에서 한 번만 반복하는 것이을 사용하는 것보다 두 배 빠르다는 것을 보여줍니다 count.


37
에 검은 금요일 할인이 text.count()있습니까?
Eric Duminil

3
@EricDuminil 당신은 좋은 점을 가지고 있지만, text.count파이썬 수준의 해석이 느린 루프와 달리 고속 컴파일 언어 (예 : C)로 이루어 지므로 할인이 있습니다.
John1024

각 숫자를 개별적으로 계산하는 것은 매우 비효율적이지만 일정한 시간이므로 여전히 O (n)입니다.
Loren Pechtel

11
사용하도록 제안한 옵션 count은 겹치는 패턴을 계산하지 않으므로 올바르지 않습니다. 참고 '111'.count('11') == 1우리가 될 것으로 기대 것이다 때 2.
Cireo

2
또한, 귀하의 "간단한 O(n)해결책은"실제로 O(10**d * n)으로 d검색 자리의 수와 n문자열의 전체 길이. 두 번째는 O(n)시간과 O(10**d + n)공간입니다.
Eric Duminil

10

"consensus"O (n) 알고리즘의 NumPy 구현은 다음과 같습니다. 모든 삼중 항과 빈을 살펴보십시오. 비닝은 "385"가 발생하면 O (1) 연산 인 bin [3, 8, 5]에 1을 추가하여 수행됩니다. 쓰레기통은 10x10x10입방체 로 배열됩니다 . 비닝이 완전히 벡터화되므로 코드에 루프가 없습니다.

def setup_data(n):
    import random
    digits = "0123456789"
    return dict(text = ''.join(random.choice(digits) for i in range(n)))

def f_np(text):
    # Get the data into NumPy
    import numpy as np
    a = np.frombuffer(bytes(text, 'utf8'), dtype=np.uint8) - ord('0')
    # Rolling triplets
    a3 = np.lib.stride_tricks.as_strided(a, (3, a.size-2), 2*a.strides)

    bins = np.zeros((10, 10, 10), dtype=int)
    # Next line performs O(n) binning
    np.add.at(bins, tuple(a3), 1)
    # Filtering is left as an exercise
    return bins.ravel()

def f_py(text):
    counts = [0] * 1000
    for idx in range(len(text)-2):
        counts[int(text[idx:idx+3])] += 1
    return counts

import numpy as np
import types
from timeit import timeit
for n in (10, 1000, 1000000):
    data = setup_data(n)
    ref = f_np(**data)
    print(f'n = {n}')
    for name, func in list(globals().items()):
        if not name.startswith('f_') or not isinstance(func, types.FunctionType):
            continue
        try:
            assert np.all(ref == func(**data))
            print("{:16s}{:16.8f} ms".format(name[2:], timeit(
                'f(**data)', globals={'f':func, 'data':data}, number=10)*100))
        except:
            print("{:16s} apparently crashed".format(name[2:]))

당연히 NumPy는 대용량 데이터 세트에서 @Daniel의 순수 Python 솔루션보다 약간 빠릅니다. 샘플 출력 :

# n = 10
# np                    0.03481400 ms
# py                    0.00669330 ms
# n = 1000
# np                    0.11215360 ms
# py                    0.34836530 ms
# n = 1000000
# np                   82.46765980 ms
# py                  360.51235450 ms

NumPy가 효율적인 색인을 사용하여 3D 행렬로 구현하지 않는 한 중첩 된 빈 대신 숫자 문자열을 평평하게하는 것이 아마 훨씬 빠릅니다. 어떤 버전의 @ Daniel 's와 시간을 냈습니까? 각 정수에 대한 문자열 검색을 실행하는 것 또는 히스토그램이있는 것?
Peter Cordes

2
@PeterCordes 나는 그것을 의심한다. ndarray핵심 numpy 유형 인 s는 다차원 배열의 효율적인 저장, 조작 및 색인 생성에 관한 것입니다. 때로는 평평하게하여 몇 %를 깎을 수 있지만,이 경우 100 x [0] + 10 x [1] + x [2]를 손으로하면 크게 도움이되지 않습니다. @Daniel이 더 빠르다고 말한 것을 사용했습니다. 벤치 코드를 직접 확인할 수 있습니다.
Paul Panzer

실제로 NumPy (또는 일반적으로 Python; x86에 대한 C 및 어셈블리 성능 조정)를 모르지만 단일 3D 배열이 있다고 생각합니까? 나는 당신이 실제로 중첩 된 파이썬 객체를 가지고 있고 별도로 색인을 작성하고 있다는 영어 텍스트 (명확히 읽지조차 않았 음)에서 생각하고있었습니다. 그러나 그것은 사실이 아니므로 nvm 내 첫 의견입니다.
Peter Cordes

필자가 사용한 순수한 파이썬 버전은 훨씬 더 높은 투표 응답이 사용한 것과 거의 동일한 히스토그램 구현이라고 생각하지만, 파이썬으로 작성하는 다른 방법이 속도에 많은 영향을 미친다면.
Peter Cordes

3

다음과 같이 문제를 해결할 것입니다.

def find_numbers(str_num):
    final_dict = {}
    buffer = {}
    for idx in range(len(str_num) - 3):
        num = int(str_num[idx:idx + 3])
        if num not in buffer:
            buffer[num] = 0
        buffer[num] += 1
        if buffer[num] > 1:
            final_dict[num] = buffer[num]
    return final_dict

예제 문자열에 적용하면 다음이 생성됩니다.

>>> find_numbers("123412345123456")
{345: 2, 234: 3, 123: 3}

이 솔루션은 제공된 문자열의 길이가 n 인 O (n)에서 실행되며 가장 좋은 방법이라고 생각합니다.


간단하게 사용할 수 있습니다 Counter. 은 필요하지 않으며 final_dict반복 할 때마다 업데이트 할 필요가 없습니다.
Eric Duminil

2

내 이해에 따라, 당신은 일정한 시간에 솔루션을 가질 수 없습니다. 문자열을 가정하면 백만 자리수 이상의 패스를 한 번 이상 받아야합니다. 백만 길이의 숫자에 대해 3 자리 롤링 반복을 수행하고 해시 키가 이미 존재하는 경우 값을 1 씩 늘리거나 이미 존재하지 않는 경우 새 해시 키 (값 1로 초기화 됨)를 작성할 수 있습니다 사전.

코드는 다음과 같습니다.

def calc_repeating_digits(number):

    hash = {}

    for i in range(len(str(number))-2):

        current_three_digits = number[i:i+3]
        if current_three_digits in hash.keys():
            hash[current_three_digits] += 1

        else:
            hash[current_three_digits] = 1

    return hash

항목 값이 1보다 큰 키로 필터링 할 수 있습니다.


2

다른 답변에서 언급했듯이 적어도 n 자리를 봐야하기 때문에이 알고리즘을 일정한 시간에 수행 할 수 없습니다. 선형 시간이 가장 빠릅니다.

그러나 O (1) 공간 에서 알고리즘을 수행 할 수 있습니다. . 각 3 자리 숫자의 개수 만 저장하면되므로 1000 개의 항목이 필요합니다. 그런 다음 숫자를 스트리밍 할 수 있습니다.

내 생각에 그들은 면접관이 당신에게 해결책을 줬을 때 잘못 찌르거나 "일정한 공간"이라고 말했을 때 "일정한 시간"을 mi을 것입니다.


다른 사람들이 지적했듯이 히스토그램 접근법은 O(10**d)여분의 공간이며 d찾고있는 십진수의 수입니다.
Peter Cordes

1
사전 접근법은 n 자리에 대해 O (최소 (10 ^ d, n))입니다. 예를 들어, n = 10 ^ 9 자리이고 두 번 이상 발생하는 드문 15 자리 시퀀스를 찾으려면.
gnasher729

1

내 대답은 다음과 같습니다.

from timeit import timeit
from collections import Counter
import types
import random

def setup_data(n):
    digits = "0123456789"
    return dict(text = ''.join(random.choice(digits) for i in range(n)))


def f_counter(text):
    c = Counter()
    for i in range(len(text)-2):
        ss = text[i:i+3]
        c.update([ss])
    return (i for i in c.items() if i[1] > 1)

def f_dict(text):
    d = {}
    for i in range(len(text)-2):
        ss = text[i:i+3]
        if ss not in d:
            d[ss] = 0
        d[ss] += 1
    return ((i, d[i]) for i in d if d[i] > 1)

def f_array(text):
    a = [[[0 for _ in range(10)] for _ in range(10)] for _ in range(10)]
    for n in range(len(text)-2):
        i, j, k = (int(ss) for ss in text[n:n+3])
        a[i][j][k] += 1
    for i, b in enumerate(a):
        for j, c in enumerate(b):
            for k, d in enumerate(c):
                if d > 1: yield (f'{i}{j}{k}', d)


for n in (1E1, 1E3, 1E6):
    n = int(n)
    data = setup_data(n)
    print(f'n = {n}')
    results = {}
    for name, func in list(globals().items()):
        if not name.startswith('f_') or not isinstance(func, types.FunctionType):
            continue
        print("{:16s}{:16.8f} ms".format(name[2:], timeit(
            'results[name] = f(**data)', globals={'f':func, 'data':data, 'results':results, 'name':name}, number=10)*100))
    for r in results:
        print('{:10}: {}'.format(r, sorted(list(results[r]))[:5]))

배열 조회 방법은 매우 빠릅니다 (@ paul-panzer의 numpy 방법보다 빠름). 물론, 그것은 발전기를 반환하기 때문에 기술이 완료된 후에는 기술이 완료되지 않았기 때문에 속임수입니다. 또한 값이 이미 존재하는 경우 모든 반복을 확인할 필요가 없으므로 많은 도움이 될 것입니다.

n = 10
counter               0.10595780 ms
dict                  0.01070654 ms
array                 0.00135370 ms
f_counter : []
f_dict    : []
f_array   : []
n = 1000
counter               2.89462101 ms
dict                  0.40434612 ms
array                 0.00073838 ms
f_counter : [('008', 2), ('009', 3), ('010', 2), ('016', 2), ('017', 2)]
f_dict    : [('008', 2), ('009', 3), ('010', 2), ('016', 2), ('017', 2)]
f_array   : [('008', 2), ('009', 3), ('010', 2), ('016', 2), ('017', 2)]
n = 1000000
counter            2849.00500992 ms
dict                438.44007806 ms
array                 0.00135370 ms
f_counter : [('000', 1058), ('001', 943), ('002', 1030), ('003', 982), ('004', 1042)]
f_dict    : [('000', 1058), ('001', 943), ('002', 1030), ('003', 982), ('004', 1042)]
f_array   : [('000', 1058), ('001', 943), ('002', 1030), ('003', 982), ('004', 1042)]

1
정확히 무엇을 비교하고 있습니까? 사용하지 않는 생성기 대신 목록을 반환해서는 안됩니까?
Eric Duminil

Counters그런 식으로 사용되지 않습니다. 올바르게 사용하면 귀하의 예에서 가장 빠른 옵션이됩니다. timeit생성기를 내장 한 목록과 함께 사용하면 방법이 Counter또는 보다 느려집니다 dict. 여기를 참조 하십시오 .
Eric Duminil

마지막으로 f_array모든 문자를 먼저 int로 변환 ints = [int(c) for c in text]한 다음을 사용 하면 더 빠를 수 있습니다 i, j, k = ints[n:n+3].
Eric Duminil


1

내 해결책은 다음과 같습니다.

from collections import defaultdict
string = "103264685134845354863"
d = defaultdict(int)
for elt in range(len(string)-2):
    d[string[elt:elt+3]] += 1
d = {key: d[key] for key in d.keys() if d[key] > 1}

for 루프 (예 : True / False / None을 사용한 추가 조회 목록)에 약간의 창의력이 있으면 마지막 줄을 제거 할 수 있어야합니다. 그 시점까지 한 번 방문한 dict에서 키를 만들고 싶기 때문입니다. . 그것이 도움이되기를 바랍니다 :)


pho7의 답변을 참조하십시오 . 그리고 의견. 많은 표를 얻지 못하는지 알아 보십시오 .
greybeard

0

-C의 관점에서 말하면 -int 3 차원 배열 결과를 얻을 수 있습니다 [10] [10] [10]; -0 번째 위치에서 n-4 번째 위치로 이동하십시오. 여기서 n은 문자열 배열의 크기입니다. -각 위치에서 현재, 다음 및 다음을 확인하십시오. cntr을 resutls로 늘리십시오 [현재] [다음] [다음 다음] ++; 값을 인쇄

results[1][2][3]
results[2][3][4]
results[3][4][5]
results[4][5][6]
results[5][6][7]
results[6][7][8]
results[7][8][9]

-O (n) 시간이며, 비교가 필요하지 않습니다. -배열을 분할하고 파티션 주위의 일치 항목을 계산하여 여기에서 병렬 작업을 실행할 수 있습니다.


-1
inputStr = '123456123138276237284287434628736482376487234682734682736487263482736487236482634'

count = {}
for i in range(len(inputStr) - 2):
    subNum = int(inputStr[i:i+3])
    if subNum not in count:
        count[subNum] = 1
    else:
        count[subNum] += 1

print count

귀하의 답변에 감사하지만 5-6 일 전에 @abhishek arora가 제공 한 알고리즘과 너무 유사합니다. 또한 원래 질문은 알고리즘을 요구하는 것이 아니라 다른 질문 (이미 여러 번 답변 됨)
its.david
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.