https://programmers.co.kr/learn/courses/30/lessons/12951

 

코딩테스트 연습 - JadenCase 문자열 만들기

JadenCase란 모든 단어의 첫 문자가 대문자이고, 그 외의 알파벳은 소문자인 문자열입니다. 문자열 s가 주어졌을 때, s를 JadenCase로 바꾼 문자열을 리턴하는 함수, solution을 완성해주세요. 제한 조건

programmers.co.kr

 

안녕하세요! 오늘은 JadenCase 문자열 만들기 문제를 다뤄보겠습니다.

저는 두 개의 정답이 나왔는데요.

1. 간결하지만 join함수를 사용하는 알고리즘

2. 1보단 덜 간결하지만 join함수를 사용하지 않아, 보다 직관적인 코드

 

제 개인적인 생각으로는 2번이 좋은 코드라고 생각하는데 다들 짧은 코드를 칭찬하시더라구요!

무슨 코드가 더 좋은 코드인지는 더 알아가야 할 것 같습니다. 

 

 


1. 문제 설명

위의 링크에 접속하시면 문제가 나옵니다.

제가 중요하게 생각했던 부분은

1. 첫 글자만 대문자이고(숫자나 문자일 경우에는 그대로)

2. 나머지 글자는 모두 소문자이다(숫자, 문자는 위와 같습니다.)

3. 공백 값도 고려해야 한다. 

입니다!

 

제일 어려웠던 부분은 3. 공백 값도 고려한다는 부분인데요, 

만약 "   banana" 가 input으로 들어왔다면, "  Banana" 가 출력되어야 합니다.

공백을 버리면 안되고, 공백은 문자로 취급하지 않습니다. 

 


2. split(), join(), upper(), lower() 함수와 코드 설명 

2-1. split() 함수 

#앞으로 설명을 위해 문자열을 str, 리스트를 lis라고 칭하겠습니다!

 

str.split(' ') 

= 문자열 str을 ' '(공백)으로 구분하여, 리스트를 반환하겠다. 라는 뜻입니다. 

str="a b c" 라면, str.split(' ')=["a", "b", "c"] 가 됩니다. 

 

str.split() 

이러한 형태의 함수 또한

str="a b c"라면, str.split()=["a", "b", "c"]가 됩니다.

 

하지만 둘의 차이점은 str.split(' ') 은 확실히 공백이 구분자인 것입니다.

 

만약 str="vvBanana" (여기서 v는 공백입니다. 스페이스요) 라면

 

str.split(' ')=["", "","banana"] 로 구분될 수 있습니다.

앞의 공백 또한 구분자로 여겨 ""v"" (빈 문자열-v-빈문자열) 의 형태로 인식합니다. 

vvbanana는 "" v "" v banana -> ["", "", banana] 의 형태가 됩니다. 

 

반면에,

str.split()=["banana"]의 형태가 됩니다. 

2-2 join() 함수

join() 함수는 split()과 반대로, 리스트를 문자열로 바꿔주는 함수입니다. 

input: 리스트 output: 문자열

 

기본적인 형태는

"구분자".join(lis) 

로, lis(리스트)에 있는 값들 사이사이에 구분자를 넣은 문자열을 반환하여줍니다.

 

lis=['a', 'b', 'c']

" ".join(lis) 는 "a b c" 입니다. 

 

2-3 upper() 함수

upper() 함수는 문자열을 모두 대믄자로 변환해주는 함수입니다. 

str.upper() 

구조로 사용하면됩니다. 

2-4 lower() 함수

lower() 함수는 문자열을 모두 소문자로 변환해주는 함수입니다. 

str.lower() 

구조로 사용하면 됩니다. 

 

저는 총 코드를 두 개 제출했습니다.

 

1번)

def solution(s):
    words=s.split(' ') #공백을 기준으로 분할 (빈 문자열이 포함 됨)

    answer=[w[0].upper()+w[1:].lower()+' ' if w!='' else ' ' for w in words]

    return ''.join(answer)[:-1] #문자열로 반환하기 위함

여기서 

answer=[w[0].upper()+w[1:].lower()+' ' if w!='' else ' ' for w in words] 

의 구조를 설명해보겠습니다. 

반환형이 리스트이기 때문에 리스트 안에 for과 if문을 넣었습니다. 

 

공백을 기준으로 분할된 문자열의 리스트를 기준으로 for문 반복합니다. 

각각 리스트의 요소인 w가 빈 문자열이 아니면 -> 공백이 아닌 것(문자열임)

해당 문자열의 첫번째 단어만 대문자로 바꾼 후, 

슬라이싱 기법을 사용하여 w[1:], 즉 해당 문자열의 첫 번째 단어 이후부터 마지막 단어까지 소문자로 바꿔줍니다. 

(여기서 문자열 사이에는 원래 공백이 있으므로 공백을 포함합니다. ) 

 

만약 w가 빈 문자열 이라면, 공백도 당연히 포함되어야 하기 때문에 공백을 넣어줍니다. 

 

한 문장에 리스트, if-else, for문을 다 넣기 위한 형태는 위와 같이 됩니다. 

 

 

2번)

def solution(s):
    answer = ''
    words=s.split(' ')
    for i in words:
        if i=='':
            answer+=' '
        else:
            answer+=i[0].upper()+i[1:].lower()+' '

    return answer[:-1]

 

사실 전 직관적인 것이 좋아서 이 코드가 더 좋다고 생각합니다. 

2번 같은 경우에는 answer을 빈 문자열로 설정하여, for문을 통해 answer에 문자들을 점점 더해줍니다.

for문의 내용은 위와 같습니다. (리스트의 경우를 문자열로 바꿨다고 생각하면 됩니다.) 

 

 


사실 python을 공부한 적이 없어서 문법 하나하나 찾아보는 게 시간이 많이 걸리는 것 같습니다. 

근데 언어는 자꾸 까먹으니깐... c++ c java 다 전생같네요.

 

안녕하세요! 거의 일년만에 쓰는 포스팅이네요... 

다시 차근차근 열심히 해보겠습니다! 

 


문제) n개의 숫자를 담은 배열 arr이 입력되었을 때, 이 수들의 최소공배수를 반환하는 함수를 작성하라. 

 

여기서 알아야 할 점은 

A. 숫자가 담긴 배열이 input 값이다.

B. 최소공배수를 구해야 한다. 

로 파악할 수 있습니다. 

 

A는 반복문으로 해결이 가능합니다. 

B는 최대공약수와 최소공배수의 원리와 알고리즘을 알고 있어야 해결할 수 있습니다. 

 


1. 최대공약수(gcd)를 구하는 알고리즘, 유클리드 알고리즘 Greatest Common Divisor

먼저 최대공약수를 구하는 알고리즘에 대해 알아보겠습니다. 

최대공약수를 구하는 알고리즘에는 여러가지가 있습니다.

 

시간 복잡도와 공간 복잡도를 고려하지 않는다면, 단순하게 모든 약수를 구해 리스트에 넣고 비교하는 알고리즘이 있을 수 있습니다. 두 수의 최대공약수를 구한다고 했을 때, 이 알고리즘의 시간복잡도는 O(n^2) 또는 O(n)이 됩니다. 

(두 수의 약수를 모두 구하거나, 한 개의 수만 약수를 구할 수 있기 때문입니다.)

 

최대 공약수를 구하는 가장 좋은 알고리즘은 "유클리드 알고리즘" 입니다. 

(알고리즘 수업 기말고사에 나왔던 기억이 나네요!)

 

def gcd(a,b):
    while b!=0:
        r=a%b
        a=b
        b=r
    return a

유클리드 알고리즘은 이와 같이, gcd(a, b) -> gcd(b, mod b) 와 같은 구조를 반복하는 알고리즘 입니다.

 

예를 들어 gcd(12,4)의 경우에는

gcd(12,4) 

= gcd(4,0) 이 되어 최대공약수는 a인 4가 됩니다. (b가 0이 되었기 때문에 while문이 종료되고 a값이 return 됩니다.)

 

유클리드 알고리즘의 장점은 시간복잡도가 O(logN)이라는 것입니다. 

 

2. 최소공배수(lcm)를 구하는 알고리즘, Least Common Multiple

최소공배수를 구하는데 왜 최대공약수를 구하는 알고리즘을 설명했을까요?

최소공배수와 최대공약수는 연관이 있기 때문입니다. 

a, b 두 자연수의 최대공약수 gcd 최소공배수 lcm을 구했을 때,

 

a x b = gcd x lcm 입니다. 

 

그렇게 때문에 이전에서 유클리드 알고리즘을 설명했습니다. 

 

3.  1, 2를 바탕으로 작성된 알고리즘

def gcd(a,b):
    while b!=0:
        r=a%b
        a=b
        b=r
    return a

def solution(arr):
    
    for i in range(len(arr)-1):
        temp_gcd=gcd(arr[i],arr[i+1])
        #최소공배수 구하기
        arr[i+1]=(arr[i]*arr[i+1])/temp_gcd
        print(arr)        
    

    return arr[len(arr)-1]

저는 내장함수 gcd를 사용하지 않고 제가 정의하여 사용했습니다. 

(사실 내장함수가 있는 걸 까먹었습니다... ㅎㅎ)

 

그 후, 포스팅 초반에 언급했던 것과 같이 반복문을 이용하여 최대공약수를 구한 후 최소공배수를 계산했습니다. 

lcm = a x b / gcd 이기 때문입니다. 

 

여기서 주의해야 할 점은 두 수의 최대공배수를 구하는 것이 아니라 n개의 수가 있는 배열의 최소 공배수를 구하는 것이라는 점입니다. 

 

최소공배수를 구한 후, 해당 최소공배수와 다른 수의 최소공배수를 구하는 과정을 반복해야합니다. 

 

0 1 2 3 4 5

 

리스트를 놓고 설명하면, 

0번째와 1번째의 최소공배수를 구한 값을 다시 1에 넣고

1번째와 2번째의 최소공배수를 구한 후 그 값을 다시 2에 넣습니다.

이러한 과정을 반복하여, 

마지막에는 4번째와 5번째의 최소공배수를 구한 후, 그 값을 5에 넣습니다. 

 

 

이 부분에서는 list index out of range를 항상 조심해야합니다. 

제가 항상 index range 오류가 납니다... 상기시키려고 적습니다. 

 


참고) gcd 내장함수 사용하기 

Python의 math 모듈에서는 gcd뿐만 아니라 lcm 모듈도 제공합니다. 

 

from math import gcd

def solution(arr):
    
    for i in range(len(arr)-1):
        temp_gcd=gcd(arr[i],arr[i+1])
        #최소공배수 구하기
        arr[i+1]=int((arr[i]*arr[i+1])/temp_gcd)       

    return arr[len(arr)-1]

math모듈 중 gcd 함수만 사용하기 위해, from 모듈이름 import 함수이름 의 형태로 선언했습니다. 

 

(모듈만 불러오는 것과 모들 중 하나의 함수만 불러오는 것 중 무엇이 더 효율적인지는 아직 모르겠습니다.

일단 가져온다는 점이... 이건 후에 알아봐야 할 것 같습니다.) 

 

gcd 함수를 사용했을 때, 이전 코드에서 변경해야 할 점은,

두 자연수의 곱을 최대공약수로 나눌 때 사용한 '/' 연산자 때문에 float가 반환된다는 점이었습니다.

gcd 함수는 integer만 적용할 수 있습니다. 그렇기 때문에 int형으로 변환하였습니다.  

+ Recent posts