시작 및 끝 문자가 일치하는 가장 긴 단어 목록


11

내 친구는 나에게 그가 쉽다고 말하는 문제를 주었지만, 그것을 사용하기 위해 좋은 알고리즘을 알아낼 수는 없습니다.

100 개의 임의 영어 단어가 입력되었습니다. 한 단어의 마지막 문자가 다음 단어의 첫 번째 문자와 일치하는 가장 긴 단어 문자열을 찾아야합니다. 각 단어는 한 번만 사용할 수 있습니다.

예를 들어, "cat", "dog", "that"이라는 단어가 제공된 경우 가장 긴 문자열은 "cat-> that"입니다. "mouse", "moose", "unicorn"이라는 단어를 받았다면, 가장 긴 문자열은 하나의 단어 일 것입니다. "bird", "dish", "harb"라는 단어가 제공된 경우 가장 긴 문자열은 "harb-> bird-> dish"(또는 "dish-> harb-> bird"또는 "bird- > 접시-> 하브 ").

나는 이것을 주기적 순환 그래프로 모델링하는 아이디어를 생각해 냈습니다. 각 노드는 단어 일 뿐이며이 단어로 끝나는 문자로 시작하는 각 단어 / 노드로 꼭지점이 있습니다.

+-------+         \ +------+
|  cat  |-----------| that |
+-------+         / +------+
    |                  |
   \|/                 |
+-------+ /            |
|  the  |--------------+
+-------+ \

이 문제는 가장 긴 경로 검색 인 것으로 보입니다 ( NP-Hard).

더 좋은 방법이 있습니까? 아니면 어떤 종류의 근사 알고리즘을 사용할 수 있습니까? 아니면 검색 공간을 줄이기 위해 영어 품질을 활용할 수있는 방법이 있습니까?


4
100 단어로, 당신은 (적어도) 100을 얻습니다! = 9.332622e + 157 조합. 그것으로 행운을 빕니다, 나는 당신의 친구가 이것이 쉽다고 말하는 당신의 다리를 당기고 있다고 생각합니다.
Martin Wickman

1
그러나 가능한 조합의 수는 그보다 훨씬 적습니다. 평균적으로 한 단어는 약 6 또는 7 개의 다른 단어에만 연결되기 때문입니다.
Abe Tool

2
이것이 가장 긴 경로 검색이라는 것이 맞습니다. 네 친구가 틀린 것 같아 그러나 철저한 검색은 코딩하기 어렵지 않으며 그렇게 오래 실행되지 않을 수도 있습니다.
케빈 클라인

4
그냥 재미로, 루비 ( gist.github.com/anonymous/6225361 ) 에서 ( @kevincline이 지적한 것처럼) 무차별 강제 검색을 코딩했습니다 . 100 단어로 ~ 96 초 만 걸렸습니다 ( gist.github.com/anonymous/6225364 ). 그리고 이것은 매우 비효율적이고 최적화되지 않은 해석 언어, 빠르고 더러운 스크립트였습니다. 따라서 100 단어만으로도 느린 버전의 무차별적인 힘도 제 시간에 실행됩니다. 내 코드는 실제로 비순환 그래프를 만든 다음 검색하지 않고 각 단어에서 시작하여 가능한 모든 경로를 재귀 적으로 작성하고 가장 긴 경로를 추적합니다.
Ben Lee

3
문제는 100 단어가 있음을 나타냅니다. 나는 이것이 당신이 언급하는 기사에서 언급 된 동적 프로그래밍 솔루션을 적용 할 수 있음을 의미한다고 생각합니다.
Julien Guertault

답변:


5

나는 이것이 당신이 언급 한 가장 긴 경로 (LP) 문제와 관련이 있다고 생각하지만 조금 다릅니다. 주요 차이점은 LP 문제가 제안 된 문제보다 연결성이 높다는 것입니다. 마지막 글자와 첫 글자로 연결을 제한하면 많은 잠재적 조합을 제거 할 수 있습니다.

이 문제를 해결하는 방법은 다음과 같습니다.

  1. 목록의 각 단어에 대해 가능한 연결 수와 연결 수를 세십시오.
  2. 0과 0이있는 단어는 버립니다.
  3. 인 및 아웃 수가 가장 적은 초기 "시작 단어"세트를 식별하십시오. 아웃은 0보다 커야합니다.
  4. 각 스타터 단어는 고유 한 입력 / 출력 연결 수의 사본을받습니다. 이것은 체인의 머리를 형성합니다.
  5. 각 체인에 대해 다음을 기반으로 "다음 단어"목록을 식별하십시오.
    • 초보의 마지막 편지 또는 이전 단어
    • 인 및 아웃 연결 수가 가장 적습니다 (다시 말해 아웃은 0보다 커야합니다).
  6. 각각에 대해 next word체인이 종료 될 때까지 5 단계를 반복하십시오.

명심하십시오 :

  • 체인의 길이를 추적하고 가장 긴 체인을 식별하기위한 글로벌 메커니즘이 있어야합니다.

  • 재귀 루프를 피하려면 연결 수의 작업 복사본에서 각 단어를 제거해야합니다.

  • 어떤 시점에서, 당신의 체인은 종료 될 것이고 당신은 0 연결 카운트를 가진 단어를 선택해야합니다.

  • 단어가 작업 목록에서 제거 될 때 입력 / 출력을 다시 계산해야 할 수도 있습니다. 언뜻보기에는 전체 세트가 상대적으로 작기 때문에 이것이 필요하다고 생각하지 않습니다. 1000 단어로 확장 한 경우 정적 카운트를 사용하면 알고리즘 수렴 속도가 느려질 수 있습니다.

나는 이것을 포장 문제로 보았습니다. 나에게 연결 안팎은 포장 할 모양을 식별합니다. 연결이 낮을수록 모양이 더 이상합니다. 모양이 더 이상할수록 체인에 넣을 때 이상한 모양을 채울 수있는 확률이 줄어듦에 따라 더 빨리 포장하고 싶습니다.

예로서:

{dog, gopher, alpha, cube, elegant, this, that, bart}

dog     0, 1
gopher  1, 0
alpha   0, 0
cube    0, 1
elegant 1, 2
this    3, 0
that    2, 1
bart    0, 2

//alpha is dropped with 0 in and 0 out.
//two candidates found: dog, cube

//chain 1
dog => gopher
//chain 2
cube => elegant => that => this

//Note 1: the following chain won't occur due to selection rules
//that takes priority over this because of output count
cube => elegant => this

//Note 2: this chain won't occur either due to selection rules
bart => that => this

2
이 알고리즘이 항상 가장 긴 경로를 찾을 것이라는 보장이 있습니까? 머리 꼭대기에서 나는 반례를 생각할 수 없지만 이것은 "로컬 최대"유형 솔루션에 해당하는 것처럼 보입니다.
Ben Lee

@ BenLee-저는 소프트웨어 엔지니어입니다. 내 코드를 보장하지 않습니다. :-) 진지하게, 나는 당신의 질문에 대한 답을 모른다. 내 이론과 수학적 증명 기술은 약하기 때문에 약하게 표현하기 때문에 경험적 평가 이상의 알고리즘을 검증 할 방법이 없습니다. 이 문제가 실제로 NP-hard인지 확실하지 않지만 해당 주장을 확인할 수는 없습니다. 그것이 NP-hard가 아니라면 알고리즘을 검증 할 수단이 있어야합니다.

2
"dog, gopher, bun, nun, noon, nub"와 같은 단어 목록은 어떻습니까? 알고리즘은 실제로 "bun, nun, noon, nub"의 조합 인 경우 가장 긴 목록을 "dog-> gopher"로 잘못 선택합니다.
Abe Tool

1
@AbeTool-좋은 예가 있습니다. 그런 다음 "최저 입력> = 1"및 "최저 출력> = 1"조합을 허용하기 위해 또 다른 반복 (또는 2)을 추가합니다.

2
나는 그것이 모든 경우에 문제를 해결할 것이라고 생각하지 않습니다. 이것이 "로컬 최대"유형 솔루션에 해당한다고 생각합니다.
Abe Tool

3

26X26 행렬을 정점의 직접 그래프를 각 알파벳으로, 단어를 가장자리로 나타내도록 만듭니다. 예를 들어-APPLE은 정점 A와 E를 A에서 E로 향한 모서리와 연결합니다. 이제 문제는 그래프에서 가장 큰 유 레리 안 트레일 (최대 모서리 수를 포함하는 경로, 정점 반복이 가능한 경우 각 모서리를 방문하는 경로)을 찾는 것으로 줄어 듭니다. O (E) 알고리즘 중 하나는 한 쌍의 꼭짓점에서 무작위로 시작하는 것입니다. 그들 사이의 길을 찾으십시오. 가능할 때까지 경로를 편안하게 유지하십시오.

@ GlenH7 업데이트 최근에 www.hackerearth / jda에서 비슷한 질문을 해결했습니다. 최상의 솔루션과 관련하여 상대적인 점수가 있었고 다음과 같은 접근법으로 가장 높은 점수를 얻었습니다.

주어진 단어 목록. 그들에 의해 형성 될 수있는 가장 긴 체인을 찾으십시오. 모든 단어가 마지막 단어의 끝에서 * 끝으로 시작하는 경우 체인은 유효합니다.

접근 =

1) 알파벳의 그래프를 꼭짓점으로 만들고 단어를 가장자리로 만듭니다. 여러 모서리를 사용하는 대신 모서리 수와 동일한 무게를 가진 모서리를 사용하십시오.

2) 최대 모서리로 그래프의 강하게 연결된 구성 요소를 찾습니다. 다른 가장자리는 일시적으로 버립니다.

3) 각 꼭짓점에 대해 그 정도가 바깥 쪽과 같아야합니다.

4) 이제 그래프에 유러 회로가 존재합니다. 그것을 찾아라.

5) 이제 남아있는 그래프에서 (wrt orignal graph는 선택된 강하게 연결된 구성 요소에서 첫 번째 꼭지점이있는 가장 긴 흔적을 찾습니다. 이것은 NP가 어렵다고 생각합니다.

6) Eulerian 회로를 트레일로 변환하는 Elerian 회로에 위의 트레일을 포함시킵니다.

이유-나는이 질문이 아마도 NP 하드 (수학적으로 말하는 것이 아니라 추측)라는 것을 받아들입니다. 그러나 위의 접근법은 균일하게 분포 된 단어의 긴 목록 (1000 +)이있을 때 가장 효과적입니다 (즉, 위의 접근법에 대한 화장실이 아닙니다). 주어진 목록을 위에서 언급 한 그래프로 변환 한 후 운 좋게 유러 리아 그래프로 밝혀졌습니다 ( http://en.wikipedia.org/wiki/Eulerian_path 참조 ) 의심의 여지없이 우리는 그 대답을 말할 수 있습니다 위의 질문은 P이며 실제로 그래프의 유러 경로입니다 ( http://www.graph-magics.com/articles/euler.php 참조 매우 간단한 접근 방식은 그래프가 있는지 확인하십시오. 단일 http://www.geeksforgeeks.org/strongly-connected-components/단일 scc에 대한 오일러 경로가 존재하기 때문에 다른 작은 scc를 일시적으로 청소하지 않는 경우). 따라서 운이 좋지 않은 경우 (거의 모든 경우에 해당) 나는 운이 좋은 경우로 변환하려고합니다 (즉, 오일러 트레일 조건이 충족됩니다). 이것을하는 방법? 관련이없는 가장자리 (정도보다 외도가 높은 정점에서 쳐다보고 경로가 아닌 정도의 정점에서 끝나는 경로의 가장자리 집합)에 대한 깊이 검색을 시도했습니다. 깊이 검색을 늘리면 먼저 경로의 두 가장자리보다 경로에서 하나의 가장자리 집합을 모두 검색했음을 의미합니다. 처음에는 i 번째 깊이 검색에 O (nodes ^ i)가 걸리기 때문에 운이 좋은 경우가 될 때까지 O (nodes + nodes ^ 2 + nodes ^ 3 + ....)의 총 시간 복잡성이있을 수 있습니다. 그러나 할부 상환 분석은 O (에지)라고 생각합니다. 운이 좋은 경우 감소하면 유러 회로를 찾으십시오.

여기까지 다항식 시간이었다. 이것은 거의 최고의 솔루션을 제공합니다. 그러나 솔루션을 더 높이려면 (완벽한 솔루션은 NP가 어렵습니다.) 남은 그래프에서 욕심 많은 접근 방식을 사용하여 선택한 scc의 정점 중 하나를 쳐다 보는 긴 흔적을 찾으십시오. 이제 이것을 발견 한 유레일 트레일에 추가하여 추가로 늘리십시오.


@ GlenH7 최근에 www.hackerearth / jda에서 비슷한 질문을 해결했습니다. 최상의 솔루션에 대한 상대 점수가 있었고 다음과 같은 접근법으로 가장 높은 점수를 받았습니다.
vishfrnds

0

생각:

먼저 알파벳 문자에서 단어까지 두 개의 맵 (해시) (예 : S 및 E)을 작성하십시오. 첫 번째 S는 시작 문자를 단어에 매핑하고 두 번째 E는 끝 문자와 동일하게 수행합니다.

예를 들어 사전이 다음과 같은 경우

새, 요리, 개, 하프

우리는 :

S:

a -> [ ]
b -> [ bird ]
c -> [ ]
d -> [ dish, dog ]
...
h -> [ harb ]
...

과,

E:

a -> [ ]
b -> [ harb ]
c -> [ ]
d -> [ bird ]
...
g -> [ dog ]
h -> [ dish ]
...

다음으로 빠른 조회를 위해 S와 E를 사용하여 사전과 같은 크기의 각 단어에 루트를 사용하고 단어가 트리에 두 번 이상 나타나지 않도록하는 포리스트 (나무 세트)를 만듭니다. 당신이 그들을 만들 때 나무의 깊이 :

bird (depth: 2)
   dish
      harb
   dog

dish (depth: 3)
   harb
      bird
         dog

dog (depth: 0)

harb (depth: 2)
   bird
      dish
      dog

마지막으로 숲을 반복하여 가장 깊이있는 나무를 찾습니다.

솔루션은 해당 트리의 하위 축에 있습니다.

예 :

dish / harb / bird / dog

위.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.