레벨 2부터 벽을 느끼는 나..

역시 물 실버였다.


코딩테스트 연습 - 정렬 - K번째 수


-내 코드-

def solution(array, commands):
    answer = []

    for cmd in commands:
        i, j, k = cmd
        array_processed = sorted(array[i-1:j])
        answer.append(array_processed[k-1])

    return answer

딱 눈에 보이고 이해되는 대로 풀었다.


-신박한 풀이-

def solution(array, commands):
    return list(map(lambda x:sorted(array[x[0]-1:x[1]])[x[2]-1], commands))

허허.. 차근차근 알아보자

i, j, k는 반드시 세 개다

array를 [i-1 : j]까지 슬라이스, 정렬한다.

 

그렇게 정렬된 배열의 인덱스가 k-1인 값(k번째 값)을 찾는다.

이 원리로, lambda를 이용해서 commands에 있는 x([2,5,3], [4,4,1], [1,7,3])을 매핑하고

리스트로 변환해서 반환한다.



코딩테스트 연습 - 정렬 - H-index

 


-내 코드-

def solution(citations):
    cit = sorted(citations) #citations을 정렬한다.
    n = len(citations)

    for i in range(n):
        if cit[i] >= n-i:   #정렬된 cit에서 한칸씩 가다가 그 값이 나머지 길이보다 크거나 같다면
            return n-i  #그 편수가 h다.

    return 0    #n = 1일 때

처음에는 정렬하고 역순으로 탐색하는 식으로 생각하다가,

오름차순으로 하는게 정배겠구나 싶었다.


 

-신박한 풀이-

def solution(citations):
    citations.sort(reverse=True)
    answer = max(map(min, enumerate(citations, start=1)))
    return answer

내가 해석한 바로는 이렇다.

 

그래프로 생각하지는 않았겠지만..

문제 이해 능력 & 코딩 능력이 어마무시한 사람들이구나 싶다..



코딩테스트 연습 - 정렬 - 가장 큰 수


-틀린 내 코드-

lst = [3, 30, 34, 5, 9]일 때,

sorted(lst) - 정수형으로 lst를 받기 때문에, 정렬해주면 큰 숫자 순서대로 정렬한다.

list(map(str, lst)) - 문자열로 바꿔준다.

sorted(lst, reverse=True) 역순으로 정렬한다.

(이 때, 문자열을 기준으로 정렬하게 되면 각 원소의 첫 글자의  ascii코드 값만으로 정렬한다.)

그 다음 for문을 이용해서,

lst를 쭉 돌아가면서 만약 다음 원소를 뒤에 붙인 수가 앞에 붙인 수보다 작다면

그 둘의 위치를 바꿔준다.

 

위 lst에서는 '30'과 '3'의 경우에 서로 위치를 바꿔주는 것이었다.

(303 < 330)

 

answer = 그렇게 바뀐 lst를 공백없이 쭉~ 붙여서 쓴 것이고,

answer = '000'같은 경우를 제거하기 위해서 int로 바꿨다가 다시 str형으로 바꾼다.

(제출을 문자열로 해야하므로)

 

그리고 그렇게 해서 냈는데..

 

ㅜㅜ

알았다.

내가 해놓은 for문은 '한번' 돌아가는 것 밖에 안 된다.

즉, 바뀌고난 후에도 최적의 수가 있을 수 있는데 그걸 반영을 못 하는 것이다.

그럼.. 어케해야하지?

 


찾아보았다.

 

문자열에서 인덱스에 따라 같은 값이라면 그 다음 문자의 ascii값을 비교한다.

맨 앞의 index 값부터 ascii 값으로 비교하기 때문에, False가 나온다.

'34'까지는 같지만 그 뒤의 '5'와 '4'를 비교했을 때 다르므로 False가 나온다.

 

이를 이용해서 입력되는 수의 상한이 1000이므로, 숫자로 이루어진 문자열에 *3을 이용한다.

왜 *3 일까?

 

예를들어, 121과 12가 있다고 치자.

'12' '121'이 나와야 가장 큰 수인데,

121121121과 121212를 따져보면,

앞의 '121'까지는 똑같고, 그 다음에서 '1'과 '2'로 갈리기 때문에, 어떤 것이 앞에 와야하는 지 알 수 있기 때문이다.

 

만약 *2 였다면?

9과 991이 있다고 쳐보자.

'9' '991'이 되어야 가장 큰 수인데,

 

99

991991

위 꼴에서는 '99'를 기준으로 991이 앞으로 오기 때문에, *3을 해주는 것이다.

(일의 자리 수를 세 자리수와 비교하기 위함.)

 

-수정한 코드-

def solution(lst):
    lst = list(map(str, lst))
    lst.sort(key = lambda x : x*3, reverse=True)

    answer = str(int((''.join(lst))))
    return answer

아.. 어렵다

 

++

import functools

def comparator(a,b):
    t1 = a+b
    t2 = b+a
    return (int(t1) > int(t2)) - (int(t1) < int(t2)) #  t1이 크다면 1  // t2가 크다면 -1  //  같으면 0

def solution(numbers):
    n = [str(x) for x in numbers]
    n = sorted(n, key=functools.cmp_to_key(comparator),reverse=True)
    answer = str(int(''.join(n)))
    return answer

내가 사용했던 아이디어로 푼 코드를 찾았다.

functools는 뭘까?

점투파 - 라이브러리 예제 : functools

 

cmp_to_key == comparater to key

내가 만든 함수를 key로 이용할 수 있게 끔 해주는 것이다.

return 값을 1, 0, -1의 값으로 반환해줘야 한다.

 

이게 머선소리지?

혼자 공부하는 파이썬 38강  - 콜백, 람다, map, filter


아직 다 이해하지는 못 하겠어..

cmp_to_key(내 비교기 - mycmp)를 쓰면,

class K를 (내 비교기)한테 멕여주는데,

(내 비교기)의 비교값에 따라 bool형태로 반환해주는 것 같다.

sorted의 매개변수로 key를 사용하면, 그 key 값의 조건에 맞게 오름차순으로 정렬한다.

(원소들이 문자열이므로 ascii 값 순으로 정렬)

 

functools.cmp_to_key(comparator)에 따라,

-1 ~ 1 순서로, 즉 (t1 < t2) ~ (t1 > t2)값으로 정렬해주는 것이다.

(문자열이더라도 쓰인 숫자가 다 다르니 return이 0인 값은 없다)


어쨌든.. 어떤 식으로 굴러가는지가 좀 궁금한데..

(return 1일때와 0일때는 같다)

cmp_to_key(mycmp)의 return 값이 1, 0 일 때는 그대로, -1일 때는 역순으로 정렬을 하는 것 같다.


(좌) 바교하는 두 수 - (우) return이 1, 0이었으면 초록색, -1이면 빨간색

무슨 메커니즘으로 숫자를 정해서 비교하는 건지는 잘 모르겠지만,

어쨌든 1,0과 -1을 이용해서 정/역으로 구분하고 있다는 건 알겠다.

아마 초록색 구간으로 닫히면 한 번 해보고

그 다음에 기본 순서대로 가다가

또 다시 초록색 구간으로 닫히면 해보되 이미 시행한 수라면 패스

이런 느낌이 아닐까 싶다.


lambda와 enumerate 그리고 cmp_to_key 생각할 여지를 많이 줬다.

코딩 방법과 스킬을 아느냐 모르냐의 차이도 그렇고, 어떻게 구현할 지에 대한 문제의 이해도 주요한 것 같다.

여러 개 찾아보고 풀면서 늘려야지.

 

복사했습니다!