Counter()

  1. 데이터의 갯수를 count할 때 사용함.
  2. 주로 리스트나 튜플, 문자열의 원소의 수를 count할 때 사용함.
  3. 파이썬의 collections 모듈의 Counter클래스를 사용한다.
  4. 결과값은 딕셔너리 형태로 return함
  5. 일반적인 딕셔너리 형태처럼 key값을 보고 싶으면 .keys()을 쓴다. value값을 보고 싶을 땐 .values()를 쓴다.
    하지만 print 될때는 dict_keys(), dict_values() 형태로 나오기 때문에 값들만 보고 싶으면 list() 를 쓰면 됨. 만약 keys() 혹은 values()없이 딕셔너리 형태일때 list를 쓰면 key값을 출력함
    .items()를 쓰면 (key, value)형태의 튜플을 원소로 하는 리스트를 출력함. 다만, dict_items() 형 태로 출력함. 값들만 출력하고 싶을 때는 list()를 쓴다.

리스트의 원소 count

from collections import Counter

data = [2, 2, 2, 1, 1, 3, 3, 4]

make_dict = Counter(data)



print(make_dict)
>>> Counter({2: 3, 1: 2, 3: 2, 4: 1})

print(make_dict.keys())
>>> dict_keys([2, 1, 3, 4])

print(list(make_dict.keys()))
>>> [2, 1, 3, 4]

print(make_dict.values())
>>> dict_values([3, 2, 2, 1])

print(list(make_dict.values()))
>>> [3, 2, 2, 1]

print(list(make_dict))
>>>  [2, 1, 3, 4]  # Counter()에 list()를 쓰면 key값을 출력함

print(make_dict.items())
>>> dict_items([(2, 3), (1, 2), (3, 2), (4, 1)])  # (key, value)

print(list(make_dict.items()))
>>> [(2, 3), (1, 2), (3, 2), (4, 1)]

 

문자열 원소 count

from collections import Counter

s = "hello python"

make_dict = Counter(s)

print(make_dict)
>>> Counter({'h': 2, 'e': 1, 'l': 2, 'o': 2, ' ': 1, 'p': 1, 'y': 1, 't': 1, 'n': 1})

print(make_dict.keys())
>>> dict_keys(['h', 'e', 'l', 'o', ' ', 'p', 'y', 't', 'n'])

print(list(make_dict.keys()))
>>> ['h', 'e', 'l', 'o', ' ', 'p', 'y', 't', 'n']

print(make_dict.values())
>>> dict_values([2, 1, 2, 2, 1, 1, 1, 1, 1])

print(list(make_dict.values()))
>>> [2, 1, 2, 2, 1, 1, 1, 1, 1]

print(make_dict.items())
>>> dict_items([('h', 2), ('e', 1), ('l', 2), ('o', 2), (' ', 1), ('p', 1), ('y', 1), ('t', 1), ('n', 1)])

 

most_common() : 빈도수가 높은 상위 원소들을 (key, value) 형태로 반환

⇒ ()를 쓰는걸 주의하자! 안쓰면 bound method Counter.most_common of Counter와 함께 (key, value)쌍으로 출력되지 않음

from collections import Counter

Counter('abbbbbbcccddddaaaa')
>>> Counter({'a': 5, 'b': 6, 'c': 3, 'd': 4})

Counter('abbbbbbcccddddaaaa').most_common(1)  # 빈도수가 가장 높은 하나만 출력함
>>> [('b', 6)]

Counter('abbbbbbcccddddaaaa').most_common(2)   # 빈도수가 가장 높은 두개만 출력함
>>> [('b', 6), ('a', 5)]

Counter('abbbbbbcccddddaaaa').most_common()    # most_common()안에 인자를 안써주면 모든 key값을 value값의 빈도순으로 나열함
>>> [('b', 6), ('a', 5), ('d', 4), ('c', 3)]

Counter('abbbbbbcccddddaaaa').most_common  # ()를 안써줬을 때
>>> <bound method Counter.most_common of Counter({'b': 6, 'a': 5, 'd': 4, 'c': 3})>

 

두 count를 더하기(+), 뺴기 (-) : value값을 더하거나 뺀다.(주의! 합집합, 차집합과 다름)

from collections import Counter

answer1 = Counter(['kim', 'park', 'kim', 'kim'])
print(answer1)
>>> Counter({'kim': 3, 'park': 1})

answer2 = Counter(['Jung', 'kim', 'kim'])
print(answer2)
>>> Counter({'kim': 2, 'Jung': 1})

print(answer1 +answer2)
>>> Counter({'kim': 5, 'park': 1, 'Jung': 1})

print(answer1 - answer2)
>>> Counter({'kim': 1, 'park': 1})

print(answer2 - answer1)
>>> Counter({'Jung': 1}) # count가 마이너스가 되는 것은 결과에서 뺌

 

&(교집합) 과 |(합집합)

from collections import Counter

answer1 = Counter(['kim', 'park', 'kim', 'kim'])
print(answer1)
>>> Counter({'kim': 3, 'park': 1})

answer2 = Counter(['Jung', 'kim', 'kim'])
print(answer2)
>>> Counter({'kim': 2, 'Jung': 1})


print(answer1 & answer2)
>>> Counter({'kim': 2})

print(answer1 | answer2)
>>> Counter({'kim': 3, 'park': 1, 'Jung': 1})

 

a.substract(b)

Counter()의 객체인 a에서 b의 count 값을 뺌. 단 이때는 위에서 빼기(-)와 달리 Count에 음수가 들어갈 수 있음. 단 이때는 빼기(-)와 달리 다시 값을 출력 해야만 결과가 보임

from collections import Counter

answer1 = Counter(kim=3 ,park=1)  # 위와 같은 결과임. ''을 안쓰는 것 주의. 위와 달리 리스트를 안쓰는 것에 주의!
print(answer1)
>>> Counter({'kim': 3, 'park': 1})

answer2 = Counter(kim=2, Jung=1)  # 위와 같은 결과임. ''을 안쓰는 것 주의. 위와 달리 리스트를 안쓰는 것에 주의!
print(answer2)
>>> Counter({'kim': 2, 'Jung': 1})

answer1.subtract(answer2)
print(answer1)
>>> Counter({'kim': 1, 'park': 1, 'Jung': -1})

answer2.subtract(answer1)
print(answer2)
>>> Counter({'kim': -1, 'Jung': 1, 'park': -1})

 

elements() 

카운트된 수만큼 원소를 반환. 단, 결과를 <itertools.chain at 0x7f0cffe49610> 형태로 출력하기 때문에 값을 보고 싶으면 list()를 해준다. 단, count된게 음수이면 출력하지 않는다.

cnt = Counter('abbbbbbcccddddaaaa')
print(cnt.elements())
>>>  <itertools.chain object at 0x7f0cf7e54cd0>

print(list(cnt.elements()))
>>>  ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd', 'd']
from collections import Counter

answer1 = Counter(kim=5 ,park=2) 
answer2 = Counter(kim=2, Jung=1)
answer1.subtract(answer2)
print(answer1)
>>> Counter({'kim': 3, 'park': 2, 'Jung': -1})


print(list(answer1.elements()))
>>>  ['kim', 'park', 'park']

 

dictionary를 이용하여 Counter 흉내내기

def countLetters(word):
    counter = {}
    for letter in word:
        if letter not in counter:
            counter[letter] = 0
        counter[letter] += 1
    return counter

countLetters('hello world')
>>> {'h': 1, 'e': 1, 'l': 3, 'o': 2, ' ': 1, 'w': 1, 'r': 1, 'd': 1}

문제링크

문제 설명

JadenCase란 모든 단어의 첫 문자가 대문자이고, 그 외의 알파벳은 소문자인 문자열입니다. 단, 첫 문자가 알파벳이 아닐 때에는 이어지는 알파벳은 소문자로 쓰면 됩니다. (첫 번째 입출력 예 참고)
문자열 s가 주어졌을 때, s를 JadenCase로 바꾼 문자열을 리턴하는 함수, solution을 완성해주세요.

 

제한조건

  • s는 길이 1 이상 200 이하인 문자열입니다.
  • s는 알파벳과 숫자, 공백문자(" ")로 이루어져 있습니다.
    • 숫자는 단어의 첫 문자로만 나옵니다.
    • 숫자로만 이루어진 단어는 없습니다.
    • 공백문자가 연속해서 나올 수 있습니다.

입출력 예

s return
"3people unFollowed me" "3people Unfollowed Me"
"for the last week" "For The Last Week"

 

참고

https://kmsstat01.tistory.com/entry/stringsplit

 

‘문자열’.upper() 혹은 ‘문자열’.lower()는 ‘숫자’에 적용될 경우 그대로 나옴. 따라서 위 문제의 조건을 따로 고려하지 않아도 됨. 주의! upper 혹은 lower 뒤에 ()를 안하면 값이 생성되지 않으므로 꼭 ()를 뒤에 붙이자
ex) '1b'.upper() >>> ‘1B’ , '1B'.upper() >>> ‘1b’

 

코드

def solution(s):
    sol = []
    li = s.split(' ')  # 문자열을 split(' ')하면 공백을 기준으로 잘라서 리스트로 만든다. 이때 공백이 연속으로 있으면 공백의 수 -1 개의 ''이 리스트의 원소가 됨
    for k in li:
        
        if  k == '':    # 공백이 두개 이상 연속으로 있을 경우 리스트의 원소중에 ''이 있을 것. 이를 고려해야함
            sol.append(k)
        else:
            sol.append(k[0].upper() +k[1:].lower())   # '문자열'.upper()는 '숫자'.upper()을 할 경우에도 에러 없이 그대로 출력함 
    return(' '.join(sol))

 

아래의 코드는 하드코드이므로 비추천함....

def solution(s):
    sol = []
    li = s.split(' ')  # 문자열을 split(' ')하면 공백을 기준으로 잘라서 리스트로 만든다. 이때 공백이 연속으로 있으면 공백의 수 -1 개의 ''이 리스트의 원소가 됨
    for i in li:
        if i == '':     # 공백이 두개 이상 연속으로 있을 경우 리스트의 원소중에 ''이 있을 것. 이를 고려해야함
            w = ''
        else:
            w = ''    
            for j in range(len(i)):
                if i[0]  in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' :
                    if j ==0:
                        w = w + i[0].upper()
                    else:    
                        w = w + i[j].lower()
                else:
                    if j == 0:
                        w = w + i[0]
                    else:    
                        w = w + i[j].lower()
        sol.append(w)

    return(' '.join(sol))

 

출처: 프로그래머스 코딩 테스트 연습, https://school.programmers.co.kr/learn/challenges

'프로그래머스 > lv2' 카테고리의 다른 글

lv2 게임 맵 최단거리  (1) 2022.09.21
lv2 타겟 넘버  (0) 2022.09.20
lv2 N개의 최소 공배수  (0) 2022.09.20
lv2 피보나치 수  (0) 2022.09.18
lV2 가장 큰 수  (0) 2022.09.18

string.split(sep = None) : sep를 구분자 문자열로 사용하여 문자열에 있는 단어들을 리스트의 원소로 만든 후, 문자열을 리스트로 출력함

  • sep = None이 default값임. string.split()인 경우( default인 경우 ) 연속된 공백 문자는 단일한 구분자로 간주함. 또한 문자열이 선행이나 후행 공백을 포함해도 결과 리스트는 시작과 끝에 빈 문자열을 포함하지 않음
    ex)   'a       b'.split()  # 공백 7칸     >>>  ['a', 'b']
            ' a       b '.split() # 공백 7칸    >>>  ['a', 'b']
  • default값이 아닌 sep가 주어지면, 연속된 구분자는 묶이지 않고 빈 문자열을 구분하는 것으로 간주함
    ⇒ 즉, 리스트를 생성할 때 연속된 구분자 -1개 만큼의 빈 문자열이 원소로 생김
    ex)   'a       b'.split(' ')  # 공백 7칸   >>>   ['a', '', '', '', '', '', '', 'b']  # 빈 문자열 원소 6개
            ‘a,,,,,,,b'.split(',') # 쉼표 7개  >>>   ['a', '', '', '', '', '', '', 'b']  # 빈 문자열 원소 6개
  • 공백이 나오는 문자열에 리스트함수를 쓸 경우 vs split( ‘ ‘ ) vs split() 
    ⇒ string.split()을 쓰면 빈 문자열이 생기지 않고 리스트가 생성됨
    ⇒ string.split(' ')을 쓰면 연속된 공백 -1개 만큼의 빈 문자열이 원소로 생겨난 리스트가 출력됨
    ⇒ list(string)을 쓰면 연속된 공백 만큼의 문자열이 원소로 생겨난 리스트가 출력됨
    ex)   'a       b'.split()      # 공백 7칸 >>> ['a', 'b']     # 빈 문자열 원소 0 개
            'a       b'.split(' ')   # 공백 7칸 >>> ['a', '', '', '', '', '', '', 'b']            # 빈 문자열 원소 6개
            list('a       b')         # 공백 7칸 >>> ['a', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'b']  # 빈 문자열 원소 7개

문제 링크

문제 설명

두 수의 최소공배수(Least Common Multiple)란 입력된 두 수의 배수 중 공통이 되는 가장 작은 숫자를 의미합니다. 예를 들어 2와 7의 최소공배수는 14가 됩니다. 정의를 확장해서, n개의 수의 최소공배수는 n 개의 수들의 배수 중 공통이 되는 가장 작은 숫자가 됩니다. n개의 숫자를 담은 배열 arr이 입력되었을 때 이 수들의 최소공배수를 반환하는 함수, solution을 완성해 주세요.

 

제한사항

  • arr은 길이 1이상, 15이하인 배열입니다.
  • arr의 원소는 100 이하인 자연수입니다.

 

입출력 예

arr result
[2,6,8,14] 168
[1,2,3] 6

 

풀이

  • 최대공약수는 math 라이브러리에서 gcd함수를 사용하면 됨
  • 최소공배수는 두값을 곱하고 최대 공약수로 나누었을 때의 값임. 주의! math 라이브러이에서 gcd는 정수값만 읽음 하지만 나눗셈을 하면 float이 되므로 int값으로 바꿔줘야함
  • 3개의 수에 대한 최대공약수는 두개에 대한 최대공약수와 나머지 수 사이에 다시 최대공약수를 구하면 됨
  • 3개의 수에 대한 최소공배수는 두개에 대한 최소공배수와 나머지 수 사이에 다시 최소공배수를 구하면 됨

 

코드

sol1)  최대 공약수를 함수로 만들어서 푸는 풀이

# N개의 최소공배수

def gcd(x,y):
    while x!= 0:
        y , x = x , y%x   # 주의!     y = x
                          #           x = y%x  이렇게 두줄로 쓰면 오답이 나옴. 그 이유는 위에서 할당된 y가 밑에서 적용되기 때문에
    return y    

def lcm(x,y):
    return int(x*y/gcd(x,y))

def solution(arr):
    m = arr.pop()
    n = arr.pop()
    
    l_c_m = lcm(m,n)
    while arr:
        l_c_m = lcm(l_c_m, arr.pop())
    return l_c_m

 

sol2)  math함수를 이용한 풀이

from math import gcd


def solution(num):      
    answer = num[0]
    for n in num:
        answer = int(n * answer / gcd(n, answer))

    return answer

 

출처: 프로그래머스 코딩 테스트 연습, https://school.programmers.co.kr/learn/challenges

'프로그래머스 > lv2' 카테고리의 다른 글

lv2 게임 맵 최단거리  (1) 2022.09.21
lv2 타겟 넘버  (0) 2022.09.20
lv2 JadenCase 문자열 만들기  (1) 2022.09.20
lv2 피보나치 수  (0) 2022.09.18
lV2 가장 큰 수  (0) 2022.09.18

과대적합 : 학습데이터(traing data)에는 정밀도가 높으나 시험데이터(test data)에는 정밀도가 현저하게 떨어지는 경우

 

=> 과대적합은 표본 수를 늘리거나,초모수(hyper parameter)를 조정 또는 규제화 강도를 높이는 것, 특성변수의 차원축 
      소, 통계적으로 유의하지 않는 특성변수를 제거하여 특성변수의 수 줄이기 등으로 해결함

 

과소적합: 학습데이터의 정밀도가 목표한 정밀도보다 현저하게 낮은 경우

 

=>  과소적합은 특성변수를 늘리거나 규제화를 약화시키기 혹은 다른 모형을 선택하여 해결하여야 함.

 

*validation set이 필요한 이유

train set으로 모델을 훈련하고, test set으로 모델을 검증할 경우 문제점

= > 고정된 test set으로 성능을 검증&수정하는 과정을 반복할 경우, 해당 모델은 test set에만 잘 작동하는 모델이 될 수 있음. test setoverfitting되어 새로운 데이터에는 알맞은 모델이 되지 못함.

이런 문제를 해결하기 위해 사용하는 것이 바로 Cross Validation이다.

 

 

   <holdout cross-validation>

모수추정: 데이터를 통해 모델 학습과정에서 모수추정하게 됨

초모수 선택 : 여러 개의 초모수 값을 순차적으로 학습데이터와 검증 데이터에 적용하여검증데이터의 성능예를 들어손실함수값 또는 정밀도이 학습데이터의 성능에 근접하게 하는 초모수를 선택.

(초모수 선택과정에서 validation set은 일종의 test data 역할을 하여 해당 초모수일 때의 모델의 성능을 validation set으로 점검함. 하지만 초모수 튜닝과정까지도 결국 적합한 모델을 찾는 과정임)

 

=> 모수와 초모수가 선택되면 해당 모델을 test data(unseen data)를 이용하여 성능을 점검함.

 

고정된 자료분할의 문제점 : 검증데이터가 잘 선택되면 좋은 결과를 보이고 잘못 선택되면 검증데이터의 성능이 나쁘게 나온다면 초모수의 선택이 옳은지 그른지를 판단할 수 없게 된다. , 최적의 초모수 값이 선택된 validation data에 의존함. 특히 자료의 크기가 작을 경우에는 이러한 현상이 두드러짐.

=> 이를 보완한 검증법 : k-fold cross- validation

 

 

<k-fold cross- validation>

  1. train data와 test data로 나눈 후, train data를 다시 k개의 fold로 나눈다.
  2. 첫 번째 자료분할에서 첫 (k-1)개의 foldtrain data로 간주하고 맨 마지막 foldvalidation data로 간주한다.
  3. (k-1)개의 fold로 구성된 train data를 이용하여, 초모수를 특정값으로 고정한 후 모형의 모수를 추정한다.
  4. 추정된 모형에 validation data을 적용하여 validation data의 성능( 예를 들어손실함수값 또는 정밀도)을 구하여
    $ E_1 $이라고 하자.
  5. 두 번째 foldvalidation data로 간주하고 나머지 foldtrain data로 간주하여 동일 방법으로 (이때 초모수 값은
    $ E_1 $
    일때와 같음) validation data의 성능을 구하여 $ E_2 $ 이라고 하자.
    validation data의 성능  $ E_1 $, $ E_2 $, ...., $ E_k $ 를 구한 후, 평균 $\frac{1}{k} \sum_{i=1}^{k} E_i$으로 고정된 초모수의 성능을 평가한다.(
    k-fold cross validation 동안 초모수의 값은 고정되어 있음)

장점: validation data를 어떤 것을 선택하느냐에 따라 큰 영향을 받지 않음. data수가 적을 때 k값을 증가시키면 더 많은 훈련 데이터가 반복에 사용되고 모델성능을 평균화하여 일반화 성능을 추정할 때 더 낮은 편향을 만들게 된다. k 값이 매우 높으면 교차검증의 시간이 오래걸리고 분산이 높은 추정을 만듦.(과대적합)

 

< stratified k-fold cross validation>

데이터가 불균형할 때 각 fold에서 클래스 비율이 전체 데이터에서의 클래스 비율로 유지되도록 하면서 k-fold cross validation을 실행하게 됨

 

 

 

 

(a) 높은 편향 ( train datavalidation data모두 정확도가 낮음) : 높은 편향은 underfitting을 의미함 => 특성변수를 늘리거나 규제화를 약화시키기 혹은 다른 모형을 선택하여 해결하여야 함.

(b) 높은 분산 : train datavalidation data 사이의 정확도 차이가 큼 : overfitting을 의미함

=> 표본 수를 늘리거나초모수(hyper parameter)를 조정 또는 규제화 강도를 높이는 것, 특성변수의 차원축소, 통계적으로 유의하지 않는 특성변수를 제거하여 특성변수의 수 줄이기 등으로 해결함.

(, train data의 노이즈가 많은 경우에는 표본수를 늘리는 것이 도움이 되지 못함)

 

*초모수 튜닝의 대표적인 방법 : grid search

grid search: 리스트로 저장된 여러 가지 하이퍼 파라미터값 전체를 조사하여 그 중 최적의 초모수를 구하는 방법

 

*k-fold cross validationtrain datak개의 fold로 나눈후 k번의 validation set을 사용함으로써 validation data set에는 덜 민감하도록 하였음 .하지만 test data에는 민감함. 즉 처음 datatrain datatest data로 나눌 때 선택되는 test data에 따라 모델의 성능이 판단될수 있음. 따라서 test data에도 fold를 이용한 cross-validation이 필요함을 알게 됨.

외부 루프와 내부루프의 이중 루프 구조를 통해 test data에도 fold를 이용한 cross-validation이 적용된 기술 :nested cross validation

 

 

< nested cross validation >

 

  1. 전체 데이터를 $ k_1 $분할하여 순차적으로 하나의 foldtest data로 사용하고 나머지를 train data로 사용함.
    => 
    외곽루프에  $ k_1 $개의 train test data set이 생성됨.
  2. 각각의 외곽루프마다 train data를 $ k_2 $분할하여 순차적으로 하나의 foldvalidation data로 사용하고 나머지를 train data로 사용함
    => 내부루프에 $ k_2 $개의 train-validation set이 생성됨.
  3. $ k_2 $내부루프를 이용하여 초모수를 fix하고 이를 validation data를 이용하여 성능평가하고 초모수를 바꾸어 가면서 이를 반복하여 최적의 초모수를 선택함.
  4. 이를 test data로 성능을 평가함
  5. 이러한 반복을 외곽루프로 $ k_1 $번 반복하여 test data의 성능의 척도가 $ k_1$개 구해짐.
  6. $ k_1 $개의 test data의 성능척도를 평균하여 최종성능을 구한다. 경쟁모형도 동일한 방법(nested cross validation)을 이용하여 성능을 구한 후 모형간 성능을 비교할 수있음. 

cf) 데이터가 충분히 크면 k-fold cross validation이 필요없음.

문제 링크

 

문제 설명

피보나치 수는 F(0) = 0, F(1) = 1일 때, 1 이상의 n에 대하여 F(n) = F(n-1) + F(n-2) 가 적용되는 수 입니다.

예를 들어

F(2) = F(0) + F(1) = 0 + 1 = 1
F(3) = F(1) + F(2) = 1 + 1 = 2
F(4) = F(2) + F(3) = 1 + 2 = 3
F(5) = F(3) + F(4) = 2 + 3 = 5

와 같이 이어집니다.

2 이상의 n이 입력되었을 때, n번째 피보나치 수를 1234567으로 나눈 나머지를 리턴하는 함수, solution을 완성해 주세요.

제한 사항

  • n은 1이상, 100000이하인 자연수입니다.

입출력 예

n return
3 2
5 5

입출력 예 설명

피보나치 수는 0번째부터 0, 1, 1, 2, 3, 5, ... 와 같이 이어집니다.

 

코드

  • 시간초과한 풀이

재귀함수는 시간이 매우 오래 걸림

# 피보나치 수 시간 초과 풀이

def Fibonacci(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else :
        return Fibonacci(n-1) + Fibonacci(n-2)
    
def solution(n):
    return Fibonacci(n)%1234567

 

  • test 통과한 풀이 - 리스트를 이용하여 점화식 만들기

리스트 끝부분에 append로 원소를 추가하는 것은 O(1)이므로 O(N). N은 100000이 최대 이므로 1초안에 출력 가능함

# 피보나치 수 성공한 풀이
def solution(n):
    sol = [0,1]
    for i in range(2, n+1):
        sol.append(sol[i-2] + sol[i-1])
    return sol[-1]%1234567

 

  • test 통과한 풀이 - 딕셔너리를 이용해서 점화식 만들기
def solution(n):
    answer ={}
    answer[0] = 0
    answer[1] = 1
    for i in range(2, n+1):
        answer[i] = answer[i-1] + answer[i-2]
    return answer[n]%1234567

 

 

출처: 프로그래머스 코딩 테스트 연습, https://school.programmers.co.kr/learn/challenges

 

'프로그래머스 > lv2' 카테고리의 다른 글

lv2 게임 맵 최단거리  (1) 2022.09.21
lv2 타겟 넘버  (0) 2022.09.20
lv2 JadenCase 문자열 만들기  (1) 2022.09.20
lv2 N개의 최소 공배수  (0) 2022.09.20
lV2 가장 큰 수  (0) 2022.09.18

문제 링크

문제 설명

0 또는 양의 정수가 주어졌을 때, 정수를 이어 붙여 만들 수 있는 가장 큰 수를 알아내 주세요.

예를 들어, 주어진 정수가 [6, 10, 2]라면 [6102, 6210, 1062, 1026, 2610, 2106]를 만들 수 있고, 이중 가장 큰 수는 6210입니다.

0 또는 양의 정수가 담긴 배열 numbers가 매개변수로 주어질 때, 순서를 재배치하여 만들 수 있는 가장 큰 수를 문자열로 바꾸어 return 하도록 solution 함수를 작성해주세요.

제한사항

  • numbers의 길이는 1 이상 100,000 이하입니다.
  • numbers의 원소는 0 이상 1,000 이하입니다.
  • 정답이 너무 클 수 있으니 문자열로 바꾸어 return 합니다.

입출력 예

numbers return
[6, 10, 2] “6210”
[3, 30, 34, 5, 9] “9534330”

문제풀이

  • int형의 list를 map을 사용하여 string으로 치환한 뒤, list로 변환한다.
  • 변환된 num을 sort()를 사용하여 key 조건에 맞게 정렬한다. lambda x : x * 4은 num 인자 각각의 문자열을 4번 반복한다는 뜻이다.
    • (x * 4)[:4]을 하는 이유?
      • num의 인수값이 1000 이하이므로 4자리수로 맞춘 뒤, 비교하겠다는 뜻.
  • 문자열 비교는 ASCII 값으로 치환되어 정렬된다. 먼저 첫번째 인덱스에 대해 비교하고, 그 때 승부가 안나면 두번째 인덱스에 대해 비교하고, 그 때도 승부가 안나면 세번째 인덱스를 비교한다(승부가 날 때까지). [’6’, ‘10’, ‘2’]일 때를 예를 들면 x*4이므로 ‘6666’, ‘10101010’, ‘2222’의 첫번째 인덱스 값으로 비교한다.
    • 6 = 86, 1 = 81, 2 = 82 이므로 6 > 2 > 1순으로 크다.(해당 예시는 해당 안되지만 만일 첫번째 인덱스에서 승부가 안나면 다음 인덱스로 가서 승부를 한다…이를 승부가 날 때까지 반복한다)
    • sort()의 기본 정렬 기준은 오름차순이다. reverse = True 전의 sort된 결과값은 10, 2, 6이다.
    • 이를 reverse = True를 통해 내림차순 해주면 6,2,10이 된다. 이것을 ‘‘.join(num)을 통해 문자열을 합쳐주면 된다.
    • int로 변환한 뒤, 또 str로 변환해주는 이유?
      • 모든 값이 0일 때(즉, ‘000’일때 이를 0으로 바꿔주기 위해서) int로 변환한 뒤, 다시 str로 변환한다.
         ex) int('000') >>> 0 

 

 

코드

def solution(numbers):
    numbers = list(map(str, numbers)) # O(n)
    numbers.sort(key = lambda x: (x*4)[:4], reverse=True) #O(nlogn)
    return str(int(''.join(numbers)))  # O(n)

 

sol2

def solution(numbers):
    numbers = list(map(str, numbers))  # O(n)
    numbers.sort(key = lambda x: (x*4)[:4], reverse=True)  #O(nlogn)
    if numbers[0] == '0': # 가장 큰수가 '0'이라는 것은 모든 수가 '0'인 것
        answer = '0'
    else:
        answer = ''.join(numbers)   # O(n)
    return answer

 

출처: 프로그래머스 코딩 테스트 연습, https://school.programmers.co.kr/learn/challenges

 

'프로그래머스 > lv2' 카테고리의 다른 글

lv2 게임 맵 최단거리  (1) 2022.09.21
lv2 타겟 넘버  (0) 2022.09.20
lv2 JadenCase 문자열 만들기  (1) 2022.09.20
lv2 N개의 최소 공배수  (0) 2022.09.20
lv2 피보나치 수  (0) 2022.09.18

+ Recent posts