본문 바로가기

TIL

[TIL 2024. 03. 27] 모의고사 | zip() | 부분문자열 이어붙여 문자열 만들기

모의고사

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

어떻게 풀면 좋을까?

해당 문제에서 "시험문제"는 최대 10,000개 정도다. 즉, input이 상대적으로 작게 주어진 경우이다.

그렇다면 매개변수로 주어지는 answer(정답번호를 요소로 갖는 배열)의 len()을 for문으로 반복하는 것도 가능할 것 같다.즉, 완전탐색으로 풀면 되겠다..

 

막히는 부분이 어디지?

1. answer의 길이가 어떨지 모르는데, 수포자 3명이 규칙적으로 찍는 배열의 길이가 모두 다르다.

이걸 어떻게 맞춰야 하지?

    person1 = [1,2,3,4,5]
    person2 = [2,1,2,3,2,4,2,5]
    person3 = [3,3,1,1,2,2,4,4,5,5]

 

-> 처음에는 충분히 큰 수인 임의의 n을 각 배열에 *해줌으로써, answer의 길이가 길어지는 경우에도 연산 대상이 없어서 에러가 나지는 않게 해보려고 했다.

 

하지만 애초에 임의의 n을 정하는 것도 어렵다. (n을 2000으로 정하기도 했는데, 이것은 가장 짧은 배열 길이(5)를 가지는 person1과 최대 answer길이를 단순 나눗셈한 결과였다) n을 임의의 수로 정한다고 한들 결과적으로 person1, person2, person3의 배열 길이가 들쭉날쭉한 것은 마찬가지라 개운치 않았다.

 

 

--> 다른 분들은 어떻게 푸셨는지 참고해보니, "인덱스%len(answer)"를 활용할 수 있었다.

 

예를 들어 answer = [1, 2, 3, 4, 2, 5, 2, 4, 2, 1, 3, 4, 2, 1, 5]로 주어진다면, len(answer)=15이다.

수포자별로 정답 여부를 반복문(for)으로 확인하려면 각 수포자의 index가 배열길이만큼 반복된 후에는 다시 0으로 돌아가서 반복되어야 한다.

 

인덱스%len(answer)를 사용하면 수포자1의 경우에는 "인덱스"가 01234 / 01234 / 01234로 반복된다.

수포자2의 경우는 01234567/0123456로 반복되고, 수포자3의 경우는 0123456789/01234로 깔끔하게 반복된다.


 

2. 문제에서 요구하는 출력값은 수포자1을 '1'로, 수포자2를 '2'로, 수포자3을 '3'으로 해서, 가장 많은 문제를 맞춘 사람을 출력하는 것이다. cnt_1, cnt_2, cnt_3을 구하고, max_cnt = max(cnt_1,cnt_2, cnt_3) 하고 난 후에는 어떻게 해야하지? max_cnt랑 뭘 비교해야 하지? 뇌 정지 왔었음..

 

-> cnt_1, cnt_2, cnt_3을 각각 max_cnt와 비교해서 가장 문제를 많이 맞춘 사람을 찾고, 해당 수포자를 빈 리스트에 append해주는 식으로 하면 되겠다.

 

또, 예제입력2처럼 가장 많이 맞춘 사람이 여럿일 수 있으니, 각 조건문은 모두 if문으로 해서 독립적으로 비교해야겠다.


정답코드 

def solution(answers):
    person1 = [1,2,3,4,5]
    person2 = [2,1,2,3,2,4,2,5]
    person3 = [3,3,1,1,2,2,4,4,5,5]
    cnt_1, cnt_2, cnt_3 = 0,0,0
    for i in range(len(answers)):
        i1 = i%len(person1)
        i2 = i%len(person2)
        i3 = i%len(person3)

        if person1[i1] == answers[i]:
            cnt_1 += 1
        if person2[i2] == answers[i]:
            cnt_2 += 1
        if person3[i3] == answers[i]:
            cnt_3 += 1

    max_cnt = max(cnt_1, cnt_2, cnt_3)
    result = []
    if cnt_1 == max_cnt:
        result.append(1)
    if cnt_2 == max_cnt:
        result.append(2)
    if cnt_3 == max_cnt:
        result.append(3)
    return result

 

 

enumerate를 이용해서 idx와 answer(=value)에 동시에 접근해서 이렇게 푸신 분들도 있었다.

cnt도 각각 쓸 것이 아니라, 튜플로 묶고 인덱스로 접근하는 것도 좋은 것 같다.

def solution(answers):
    person1 = [1,2,3,4,5]
    person2 = [2,1,2,3,2,4,2,5]
    person3 = [3,3,1,1,2,2,4,4,5,5]
    score = [0,0,0]
    result = []

    for idx, answer in enumerate(answers):
        if answer == person1[idx%len(person1)]:
            score[0] += 1
        if answer == person2[idx%len(person2)]:
            score[1] += 1
        if answer == person3[idx%len(person3)]:
            score[2] += 1

    for idx, s in enumerate(score):
        if s == max(score):
            result.append(idx+1)
    return result

print(solution([1,3,2,4,2]))

 


zip()

zip()은 iterable(순회 가능)한 자료형들을 인자로 받고, 이 자료형들 각각의 요소를 나눈 후 인덱스끼리 잘라서 새로운 iterable 객체를 return하는 파이썬 내장 함수이다

 

a_list = [1,2,3,4,5]
b_list = ['하나', '둘', '셋', '넷', '다섯']

print(zip(a_list,b_list))   #<zip object at 0x0000017201FE75C0> #메모리 주소가 print됨
print(type(zip(a_list,b_list)))   #<class 'zip'>
print(list(zip(a_list,b_list)))   #[(1, '하나'), (2, '둘'), (3, '셋'), (4, '넷'), (5, '다섯')]

 

 

zip문을 for문과 함께 사용하면 요소들만 깔끔하게 개행으로 출력할 수 있다

a_list = [1,2,3,4,5]
b_list = ['하나', '둘', '셋', '넷', '다섯']

for x,y in zip(a_list,b_list):
    print(x,y)

# 1 하나
# 2 둘
# 3 셋
# 4 넷
# 5 다섯

 

 

주의할 점

  • list로 묶지 않고 print하면 해당 메모리 주소가 출력된다. 왜냐하면 이때의 자료형은 zip이기 때문이다. 따라서 (우리가 원하는 형태의 값으로 출력하려면) print시에는 반드시 list로 묶어줘야 한다
  • zip()은 여러 개의 iterable을 한꺼번에 처리할 수 있다. 즉, 매개변수로 2개 이상의 iterable을 주는 것도 가능하다
a_str = "slkjl"
b_str = "lbkjn"
c_str = "qpoeo"
d_str = "dskjg"
for x,y,z,w in zip(a_str,b_str,c_str,d_str):
    print(x,y,z,w)

# s l q d
# l b p s
# k k o k
# j j e j
# l n o g

 

list_1 = [1, 2, 3, 4, 5]
list_2 = [6, 7, 8, 9, 10]
list_3 = [11, 12, 13, 14, 15]
list_4 = [16, 17, 18, 19, 20]
for x,y,z,w in zip(list_1, list_2, list_3, list_4):
    print(x,y,z,w)

# 1 6 11 16
# # 2 7 12 17
# # 3 8 13 18
# # 4 9 14 19
# # 5 10 15 20

 

  • zip()에서 함수로 넘기는 iteable은 인자 길이가 똑같게 해야 한다. 만약 길이가 다르면 가장 짧은 인자의 길이에 맞춰지고, 나머지는 버려진다.
fruit_list = ['apple','banana','mango', 'blueberry', 'cherry']
price_list = [3000, 5000, 4000, 8000]
for fruit, price in zip(fruit_list, price_list):
    print(fruit, price)

# apple 3000
# banana 5000
# mango 4000
# blueberry 8000

부분문자열 이어붙여 문자열 만들기

아직도 2차원 리스트의 인덱싱이 좀 어렵다..본의 아니게 오늘 좀 헤맨 문제다

def solution(my_strings, parts):
    answer = []
    for i,v in enumerate(parts):
        a,b = v
        answer.append(my_strings[i][a:b+1])
    return ''.join(answer)


print(solution(["progressive", "hamburger", "hammer", "ahocorasick"],	[[0, 4], [1, 2], [3, 5], [7, 7]]))
#programmers

 

 

 

 

참고자료

https://wjunsea.tistory.com/106

https://wjunsea.tistory.com/106#google_vignette