강의로 돌아가기
kuka84

첫번째 실행 결과가 오류가 납니다.

안녕하세요~

오류 로그는 다음과 같습니다.

--> 실행 결과 〉실행한 결괏값 [1, 1]이(가) 기댓값 [1, 3]와(과) 다릅니다.

계속 오류가 나는데 이유를 모르겠네요..

힌트라도 주시면 안될까요~?

작성중인 코드―solution.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def solution(L, x):
    i=0   
    M =[]
    n=0
    j=0
    y=0

    for i in L:

        if x in L:       
            j=j+1
            print(j)
            M.append(L.index(x))
            print(M)
            if M is not Null
                n = L.index(x)
                print(n)
                L = L[n+1:]
                print(L)
               # M.append(n+1+n)
                print(M)
                print('----------------------------')
                #for j in M:

    #찾는 값이 없을 때
    if M == []:
        M.append(-1)

    print(M)
    answer = []
    answer = M
    return answer
1 개의 답변
이시윤

먼저 수정해야 할 부분은, L15 의 if 문장입니다. 문법적으로도 행 끝의 콜론 (colon, :) 이 빠져 있기 때문에 오류이고, 논리적 의미로는 아마 리스트 M 이 비어 있지 않은 경우를 의도한 것 같은데, 그렇다면 if len(M) != 0 으로 쓰거나 if M != [] 으로 쓰는 것이 맞을 것입니다.

알고리즘에는 몇 가지 틀려 있는 부분이 있습니다. 우선, 쓰이지 않는 변수들이 있는데, jy 는 무엇을 의도한 것인지 모르겠습니다. 주어진 문제를 해결하기 위하여 이용되는 것이 아니라면 삭제하는 것이 좋겠습니다.

L8 에서는 for i in L: 로 시작하는데, 이 i 라는 변수 또한 그 안에서는 이용하지 않습니다. 그렇다면 이것은 올바른 순환문의 구조가 아닐 것입니다. 리스트 L 안에 있는 원소를 하나 하나 검사하는 방법을 택하거나 (그럴 경우에는 이런 구조의 순환문을 이용하겠죠) 아니면 리스트의 index() 메서드를 이용해서 (위 코드의 L13 과 L16 에 있는 것처럼) 위치를 찾는 방법 중 한 가지를 택해야 합니다.

후자의 방법을 택했다고 가정하면, 위에서 언급한 i 를 이용하는 순환문은 제거하고, L10 의 if x in L:while x in L: 로 바꾸어 순환문으로 만들 수 있습니다. 탐색 대상이 되는 리스트 (처음에는 리스트 `L` 의 전체, 하나 이상을 발견하고 난 뒤에는 L18 에 의하여 발견한 원소의 뒷쪽으로 슬라이스해낸 부분 리스트) 에 찾고자 하는 원소 `x` 가 남아 있는 동안 의 의미가 될 것입니다.

그 다음, L15 도 사실은 의미가 없습니다. 그 위에서 (L13) 발견한 인덱스를 append() 했기 때문에 리스트 M 은 비어 있는 리스트일 가능성은 없습니다. 삭제하는 것이 좋겠습니다.

이렇게 하고 나면 코드는 매우 간단해졌을 것입니다. 불필요한 부분을 더욱 제거하자면, L13 과 L16 에서 두 번 L.index(x) 를 호출하는데, 이것은 코드를 읽기에 불편해진다는 단점도 있지만 리스트 내에서 특정 원소를 찾아내는 작업을 두 번 하게 만들기 때문에 효율성 측면에서도 안좋은 영향을 줍니다. 먼저 변수 n 에 해당 내용을 담고 그 이후에 n 을 이용하여 리스트 M 에 적당한 값을 (이 적당한 값이 틀려 있음이 이 알고리즘이 올바르게 동작하지 못하는 핵심 원인인데, 그것은 잠시 후에 얘기하기로 하고) 담는 방법을 택하는 것이 좋겠습니다.

위에 언급한 핵심적인 내용을 얘기하기 전에, 마지막으로 불필요한 코드를 더 없애기로 한다면, L30 의 answer = [] 는 필요하지 않습니다. 그 바로 아래 줄에서 answer = M 으로 하고 있기 때문입니다. 더욱 중복을 없애고자 한다면, 리스트 M 을 이용하지 않고, 처음에 (L3) answer = [] 으로 하고 알고리즘 동작에서 M 대신에 모두 answer 를 이용하거나, 아니면 지금처럼 하되 answer 라는 리스트는 전혀 이용하지 않고 L32 에서 return M 으로 하면 훨씬 깔끔해집니다.

마지막으로, 이 알고리즘이 올바른 결과를 내지 못하는 가장 중요한 이유를 설명하자면, 아래와 같습니다.

L18 에서의 리스트 슬라이싱은, 지금 막 발견한 원소 x 의 위치 바로 다음부터 끝까지의 부분 리스트를 만들어 (이것을 슬라이싱이라고 부르는 것이죠) 그 결과를 다시 L 에 저장합니다. 즉, 리스트 L 을 잘라내는데, 지금 발견한 위치 뒷쪽만 남기는 것입니다.

그러고 나서는 다시 다음 원소를 발견하기 위해서 L13 에 돌아오는데, 이 때 L.index(x) 의 값을 그냥 이용하면 안됩니다. 왜냐면 리스트의 앞쪽이 달아났기 때문에 인덱스가 맞지 않아서입니다. 문제에 포함된 케이스 1 의 경우를 들어 설명하자면, 처음에는 L == [64, 72, 83, 72, 54] 인데, 따라서 찾고자 하는 원소 (x == 72) 의 인덱스를 발견하면 1 이고, M == [1] 이 됩니다. 그리고 나서 슬라이싱을 통해서 L = L[2:] 가 되므로 L == [83, 72, 54] 입니다. 다음번 찾기를 하면 L.index(x) 의 리턴 값은 1 이 되고 이것을 M.append() 하므로 이제는 M == [1, 1] 입니다.

의도한 결과는 [1, 3] 입니다. 원래 주어진 리스트 L 내에서 원소 x 가 발견되는 모든 위치의 인덱스 값을 저장한 것입니다. 이렇게 하려면, (위의 예를 통해서 이해가 될 것이라고 생각합니다.) 슬라이싱을 통해서 리스트에서 잘라낸 원소의 개수 (위에서는 변수 n 의 값보다 하나 큰 값이겠죠?) 를 쌓아 가면서, 그만큼을 L.index(x) 로 찾아낸 인덱스에 더해 주어야 할 것입니다.

위의 설명을 힌트로 해서, 코드를 보다 간결하게 수정하면서 문제를 풀어보세요. 그것이 잘 동작한다면 문제의 지문에 포함된 힌트 에서 제시한 방법을 올바르게 구현한 셈이 될 겁니다. 그 후에, (추가의 연습을 위해서) for i in len(L): 형태의 순환문을 만들어 변수 i 가 0 부터 시작해서 L 의 마지막 원소의 인덱스까지를 가지도록 하면서 L[i] == x 인지를 검사해서 그 인덱스 (변수 i 의 값) 를 결과 리스트 (위 코드에서는 M) 에 쌓는 방법도 구현해보세요. 후자의 방법이 사람이 생각하기에는 보다 직접적인 방법이어서 구현하기가 더 쉬울 겁니다. 문제의 지문에서는, 리스트가 제공하는 메서드의 활용을 연습하기 위하여 index() 와 슬라이싱을 이용하는 것이 한 가지 방법이 됨을 언급했습니다.

답변 쓰기
이 입력폼은 마크다운 문법을 지원합니다. 마크다운 가이드 를 참고하세요.