Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Programmers] KAKAO Lv2 문자열압축 #22

Merged
merged 1 commit into from
Oct 4, 2021
Merged

Conversation

seojisoosoo
Copy link
Collaborator

def solution(s):
    unit=[]
    unitlen=[]

    for i in range(1,len(s)+1):
        split_data=[]
        while 1:
            split_data.append(s[:i])
            s=s[i:]
            if len(s)==0:
                break

        nlist=[]
        for j in range(1000):
            nlist.append(0)

        k=0
        r=len(split_data)-1

        for j in range(r):            
            if split_data[j]==split_data[j+1]:
                nlist[k]=nlist[k]+1
            else:
                k=k+1
                if j==len(split_data)-2:
                    nlist=nlist[:k+1]
        for j in range(len(nlist)):
            nlist[j]=nlist[j]+1

        print(nlist)
        ncomplete=""
        for j in range(len(nlist)):
            if nlist[j]!=1:
                ncomplete=ncomplete+str(nlist[j])+split_data[0]              
            else:
                ncomplete=ncomplete+split_data[0]
               
            split_data=split_data[nlist[j]:]
            
        unit.append(ncomplete)
        for j in range(len(unit)):
            unitlen.append(len(unit[j]))
            
    return min(unitlen)

solution("aaabbc")
  1. 느낀점
    우선, 결론부터 이야기하자면 이 코드는 잘못된 코드다. 에러가 나기 때문이다... 그럼에도 이 코드로 푸쉬를 하는 이유는,,,, 사실 이 문제를 여섯 시간동안 붙잡고 있었기 때문이다. 처음에 딱 봤을 때는, 엥? 쉬운데?라고 생각을 했고, 그래서 바로 풀었는데 에러를 계속해서 해결하느라 꽤 애먹었다. 결국... 못 고쳤지만...^^ 그래도 재귀를 보다가 문자열을 보니까... 마음이 행복했다. 문자열 사랑혀... 리스트 사랑혀...

  2. 풀이방법
    음 내가 봐도 변수랑 반복문을 꽤 많이 썼다. 우선 i는 쪼갤 단위 수, split_data는 s를 i씩 잘라서 넣은 리스트, nlist는 split_data에서 옆의 요소와 비교해서 몇개가 같은지 개수를 세서 넣어둔 리스트, ncomplete는 압축한 문자열, unit은 자른 단위별로 다른 모든 ncomplete를 모은 리스트, unitlen은 unit리스트 요소의 길이를 넣어둔 리스트다. 예를 들어, unitlen[1]은 s를 1씩 잘라서 압축한 문자열 unit[1]의 길이이다.
    인덱스에러가 나는데,

if j==len(split_data)-2:
    nlist=nlist[:k+1]

이 부분에서 에러가 나는 것 같다. nlist가 원래는 0이 1000개인 리스트인데, 단위에 따라 자른 문자열에서 같은 부분이 있으면 1씩 증가시키는 방향으로 만들었고, 만약 증가값이 없으면 그를 기준으로 뒤를 자르겠다는 의미의 코드였다. 그런데, 이제 자르는 동작이 제대로 작동되지 않아서, len(nlist)이 여전히 1000인 상태가 유지되어서 뒷 코드에서도 쭉 에러가 나는 듯하다....
이미 이 아이와 너무 많은 씨름을 해서, 아예 처음부터 코드를 다시 짜보는 게 더 낫지 싶기도 하고 그렇다.

  1. 향후방향
    이 문제는 정말 다시 풀어볼 예정이다. 나는 문자열의 정말 처음부터 끝까지를 돌리는 반복문을 사용했는데, 구글링을 해보니 다들 반으로 쪼갠 개수를 이용하더라... 하긴 입력가능한 문자열의 길이가 최대 1000이니까, 처음부터 끝까지 하나하나 다 돌려보는 건 상당히 비효율적인 일일거라 생각한다. 구글링하기 싫어서 진짜 잉케저케 붙잡고 있었는데, 이 문제는 다른 사람이 푼 코드를 다시 보고 하나하나 천천히 다시 보려고 한다.

@seojisoosoo seojisoosoo added the python lang : python label Oct 2, 2021
@seojisoosoo seojisoosoo self-assigned this Oct 2, 2021
@Tarakyu
Copy link
Collaborator

Tarakyu commented Oct 3, 2021

어려운 문제인데 고생하셨어요~~

# 1

while 1:
    split_data.append(s[:i])
    s=s[i:]
    if len(s)==0:
        break

이 코드는 i가 1에서 len(s)까지 증가하면서 여러번 실행되어야 하는 함수인데, 이렇게 되면 첫 실행 때 s가 빈 문자열이 되어버려서 두 번째 실행부터는 작동을 안 해버려요.

    temp_s = s
    while 1:
        split_data.append(temp_s[:i])
        temp_s=temp_s[i:]
        if len(temp_s)==0:
            break

이런식으로 s의 복사본을 만들어서 작업하면 될 것 같아요.

# 2

#원래 코드
nlist=[]
        for j in range(1000):
            nlist.append(0)
#제안하는 코드
nlist = [0]*1000

nlist 선언할 때 이런 식으로 간단하게 선언할 수 있어요. 코드 성능과는 상관 없지만 손가락 건강을 위해..

# 3

for j in range(r):            
    if split_data[j]==split_data[j+1]:
        nlist[k]=nlist[k]+1
    else:
        k=k+1
        if j==len(split_data)-2:
            nlist=nlist[:k+1]

i = len(s)인 경우에는 for문 자체에 진입하지 않기 때문에 실행이 되지 않고, 이것 때문에 오류가 나는 거였어요.
또 nlist를 잘라주는 nlist=nlist[:k+1]가 else 밑에 가있으면 "aabbbb"를 두 개씩 "aa/bb/bb"로 끊는 경우처럼 마지막 두 개의 단위가 같은 경우에도 저 코드가 실행되지 않기 때문에 nlist 길이가 그대로 1000이 되어버려요.

for j in range(r):            
        if split_data[j]==split_data[j+1]:
            nlist[k]=nlist[k]+1
        else:
            k=k+1
nlist=nlist[:k+1]

애초에 if j==len(split_data)-2: 조건은 저 for문이 끝난 뒤 실행하고 싶다는 의도였을 텐데요, 그럼 그냥 이렇게 for문 밑에 따로 두시면 해결됩니다.

# 4

아이디어 자체는 괜찮았는데 알고리즘 문제에 쓰이는 여러 스킬들이 아직 익숙하지 않으신 것 같아요. 기계적으로 자주 쓰이는 스킬들은 개인이 혼자서 발상해내기 힘든 경우가 많아요. 그런 스킬들은 다른사람들의 풀이, 유튜브, 강의들을 참고하면서 배우는 것이 효율적일 거예요.
또 위 문제에서는 i = len(s)인 경우에 오류가 나는 것이었는데, 이런 걸 디버깅 기능을 통해 직접 찾고 해결하는 과정이 실력 향상에 많이 도움 될 거라고 생각해요.
잘 봤습니다 고생하셨어요~~

@leobang17
Copy link
Collaborator

와우 준호님 답변 ㄷㄷ


근데 저는 #2 번 같은 경우는

[0 for _ in range(1000)]

처럼 초기화하는 걸 추천해요.
저렇게 곱해주는게 1차원 배열일 경우에는 상관 없는데 2차원 이상의 n차원 배열로 넘어가면 문제가 생겨요.

배열을 곱해주면 배열의 주소값도 같이 복사되고, 동일한 객체로 인식합니다.
그러니까 만약에 10 * 10의 2차원 배열을 만든다고 하면,

a = [[0] * 10] * 10

이렇게 할 경우, 2차원 배열 a의 column은 모두 동일한 주소값을 공유하게 됩니다.
a[0][2]에 2라는 값을 할당하면 a[i][2] (0 =< i <= 9)에 모두 2가 할당됩니다.

1차원 배열에 이용할 때는 유용하지만 다차원 배열에도 습관을 들이기 위해서 for문으로 초기화하는 걸 추천합니다!

a = [[0 for _ in range(10)] for _ in range(10)]

이렇게요


이 부분에 대해서는 mutable data type, immutable data type, deep copy와 shallow copy의 키워드로 좀 더 알아보시면 이해가 될거에요.

@seojisoosoo
Copy link
Collaborator Author

와... 두 분 진짜... 이런 쓰레기같은 코드에도 찾아와주시고... 진짜 제 코드 이해하기 어려우셨을 텐데 정말정말 감사합니다.... 진짜... 열심히 해야겠다는 의지를 불러일으키는...그런...은인이십니다... 최고셔요...감사합니다 진짜루ㅜ 제가 생각했던 부분말고도 다른 데서 에러가 났다니... 찬찬히 반영해서 다시 풀어보겠습니다! 진짜진짜 넘넘 감사해요!!!!

@seojisoosoo seojisoosoo merged commit b368d4b into main Oct 4, 2021
@seojisoosoo seojisoosoo deleted the string-compression branch October 4, 2021 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
python lang : python
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants