프로그래머스의 '파이썬을 파이썬답게' 강의를 듣고 TIL을 남긴다

 

숫자와 진법을 입력하여 10진법으로 바꿔서 출력하는 문제다. 

num, base = map(int, input().strip().split(' '))

num = list(str(num))

answer = 0
turn = 0

num_enu = enumerate(num)

for idx, nn in num_enu:
    answer = answer + pow(base, len(num) - int(idx) - 1) * int(nn)

print(answer)

 

파이썬의 int 함수가 진법 변환을 지원한다.

int(x, base=10)  --10진법으로 바꿔준다

 

num = '3212'
base = 5
answer = int(num, base)
print(answer)

위의 두개의 코드를 이어서 실행시킨 터미널 화면

728x90

파이썬으로 swap 하기 

 

a, b = b, a

간단하게 두 개의 값을 swap 할 수 있다. 

 

 

파이썬으로 몫과 나머지 구하기 

print( *divmod(a, b) )

 

 

728x90

Andrew Andrew Ng 교수의 머신러닝 정리를 요약했다. 

 

첫 번째 챕터 1.2 Linear Regression with One Variable 

 

http://soopsaram.com/ml/markdowns/1.2-linear-regression-with-one-variable.html

 

1.2 Linear regression with one variable.md · GitBook

이번장에서는 Linear regression 알고리즘에 대해 알아보고 Model에 대해서 그리고 지도학습의 전체 과정에 대해서 알아볼 것이다. Linear regression은 입력된 값을 기반으로 결과값을 예측하는 알고리즘이다. 이장에서는 집값을 예측하는데 Linear regression을 사용해볼 것이다. 그것을 위해서 cost function 과 gradient descent 라는 개념에대해서 살펴볼 것이다. 위와 같은 데이터가 있을때, 1250 사

soopsaram.com

 

수식과 그림은 따로 포스팅에 첨부하지 않았다. 

 



1.2.1 Model and Cost Function

Linear regression은 입력된 값을 기반으로 결과값을 예측하는 알고리즘이다.


1.2.2 Linear regression

Supervised learning == 지도학습. 


문제와 답이 한 쌍으로 되어 있다. 이를 Training set(data set) 이라고 한다.  data set이 x와 y로 구성된다.
m: 학습 데이터 개수
x: input, feature
y: output, target


1.2.3 Model Representation

Hypothesis Function(가설 함수) 개념
머신러닝의 최종 목적은 예측을 위해 이 가설함수를 생성하는 것이다. 
데이터를 통해 학습을 진행하는 것은 함수의 parameter를 학습하는 것과 같다.
trainig set데이터가 학습 알고리즘을 거치면 결과함수가 나오는데, 이를 h라고 표기한다. 

(Hypothesis Function이라 부른다)


1.2.4 Cost Function(비용 함수, 손실 함수 ) 


Cost Function은 Hypothesis Function의 정확도를 평가하기 위한 도구다. 
h함수가 함수의 파라미터를 어떻게 선택하는지에 영향을 미친다. 
함수의 파라미터를 적절하게 선택하여 만든 h함수의 결과값과, 실제 결과값 y가 얼마나 차이가 있는지 확인하는 것이 cost function이다. 
이 차이가 적을 수록 정확한 h(가설함수)를 찾은 것이다. 
이러한 가설함수는 오차함수의 제곱이라고도 풀린다. 
이 제곱함수는 회귀분석(regression)에서 가장 많이 사용된다. 
제곱을 하는 이유는 음소, 또는 미분을 해야하기 때문이다.
자세히 살펴보면 공식자체는 별게 없다. 
training set에서 각 (예측값i - 실제값i)을 제곱하고 합을구한뒤 전체 training set 갯수 m으로 나눠서 평균을 낸것일 뿐이다.
cost function이 작아질 수록, Hypothesis Function의 정확도는 향상된다.


1.2.5 Simplified Cost function of Linear Representation

세타0을 0으로 만든 단순화 버전 
단순화시킨 h그래프는 원점을 지난다. 
세타1이 1일때(기울기가 1)는 예측 모델의 예측값이 실제값과 동일해진다는 것을 설명한다. 
세타1 == 기울기.

 


1.2.6 cost function 

세타0과 세타1이 모두 존재하므로, cost function(손실함수)는 3차원 그래프가 나온다. 
이 부분은 이해하기 어려웠음.

 


1.2.7 Parameter Learning(Gradient Descent)


이번 장에서는 가장 적합한 hypothesis function의 공식을 구성하는 parameter(세타)들을 어떻게 추정하는지 알아본다. 
Gradient Descent 알고리즘이다. 

 


1.2.8 Gradient Descent 알고리즘 수학적 정의


목적: Minimize cost function
Gradient Descent알고리즘은 Cost function, J() 의 최소값을 찾기 위해 사용한다. (최소화 문제의 경우에 많이 사용하는 범용 알고리즘이다.)

어떤 값으로 세타0와 세타1을 초기화 한다. (보통 0)
손실 함수를 최소화 시키는 방향으로 세타0과 세타1을 변화시킨다. 
Linear regression에서는 손실함수 J의 최소점이 무조건 1개이다. 

훈련비율(==학습률, learning rate): 기본적으로 언덕을 내려갈 때 얼만큼 큰 걸음을 내 딛어야 하는지를 의미한다. 기울기 하강의 변화치를 큰폭으로 할지 작은폭으로 할지에 해당한다.


1.2.9 learning rate와 미분계수 


훈련비율이 매우 작다면, 매우 작은 스탭(폭)으로 gradient가 하강한다. 
그래서 많은 이동이 필요해서 하강 속도가 느려진다.
훈련비율이 매우 크면, 결국 수렴(converge)에서 멀어지게 된다. 

 


1.2.10 Gradient Descent for Linear Regression


경사하강법을 손실함수를 최소화 하는 수식에 대입하면 된다. 


 

728x90

Elastic Search 에서 document를 대량으로 insert 하는 방법

 

 

from elasticsearch import Elasticsearch
from elasticsearch import helpers

#  ES 연결 
es = Elasticsearch([{'host': '192.168.xx.xxx', 'port': 9905}])

docs = [[123, 'aa', 'bb', 'cc'],
        [456, 'AA', 'BB', 'CC']]

for cnt in range(2):
    docs.append({
        '_index': 'id_and_values_index',
        '_type': '_doc',
        '_source': {
            'm_val': docs[cnt][0],
            'time': docs[cnt][1],
            'up_time': docs[cnt][2],
            'm_id': docs[cnt][3],
        }
    })

helpers.bulk(es, docs)
728x90

데이터프레임 data_f 을 다뤄본다 

 

import pandas as pd

data_f = pd.DataFrame()
data_f.columns = ['aa', 'bb', 'cc']

컬럼은 나중에 지정해도 된다 

Dataframe이 아니라, DataFrame 인 것을 유의 


행 단위로 순회  (for 문 안에서)

 

iloc[]으로 접근한다 

for ii in range(total_df_len):
	data_f.iloc[ii]
    

하나의 row가 'pandas.core.series.Series' 타입으로 리턴된다 

 

 

row 중에서도 특정 칼럼만 지정하여 순회 

for ii in range(total_df_len):
	data_f.iloc[ii]['m_id']
    

하나의 row가 'numpy.ndarray' 타입으로 리턴된다. 

 

 


 

열을 선택 

 

loc으로 접근 

행 인덱스 번호 와 열의 이름 간에 콤마를 이용하여 구분하는 것이 특이점

for ii in range(total_df_len):
    print(data_f.loc[ii, 'time'])
    

 

반복문을 순회하지 않고, 한번에 'time' 칼럼의 전체데이터를 가져오려면 : 를 이용한다 

print(data_f.loc[:, 'time'])

 

728x90

엘라스틱서치를 이해하기 위해 필요한 개념

 

(도서) 엘라스틱서치 실무 가이드의 9장 '엘라스틱서치와 루씬'을 읽고 내용을 간추렸다. 

http://www.yes24.com/Product/Goods/71893929

 

 

  • 클러스터

클러스터 데이터를 실제로 가지고 있는 하나 이상의 노드들로 구성된다. 연관된 노드들끼리는 하나의 클러스터의 구성원으로 연결되어야 한다. 같은 클러스터 내부의 노드들끼리만 데이터를 공유할 수 있기 때문이다. 

 

  • 노드

물리적으로 실행된 런타임 상태의 엘라스틱서치를 노드라고 한다. 

엘라스틱서치 클러스터를 운영하기 위해 하나 또는 다수의 물리 서버에 엘라스틱서치를 설치하고 실행하게 된다. 

 

  • 노드의 종류

1) 마스터노드 : 클러스터의 제어를 맡는다. 노드들의 상태를 모니터링. 색인 요청에 대한 데이터의 라우팅. 장애 발생 시 레플리카를 이용하여 샤드를 복구하는 책임을 가진다.
2) 데이터노드 : 데이터를 보유, CRUD, 검색, 집계한다. 
3) 인제스트 노드 : 색인 전 "전처리" 작업을 담당한다. 데이터 변환 등 사전 파이프라인 처리를 한다.  
4) 코디네이팅 노드 : 검색이나 집계 시 "분산 처리"만을 목적으로 설정된 노드다. 
5) 트라이브 노드 : cross cluster search(여러 클러스터에 접근하여 동시에 검색)를 제공하는 특수한 목적의 노드이다. 최신 버전에서는 폐기 예정이다.

 

  • 인덱스 

유사한 특성을 가지고 있는 문서를 모아놓은 문서들의 컬렉션. RDBMS에서 테이블의 개념과 유사하다.
유의할 점 하나는 인덱스명은 반드시 소문자여야 한다.
하나의 인덱스에는 하나의 타입만 생성해야 한다.

인덱스에 Document문서(RDBMS에서 하나의 row와 같다)들이 저장되는데, 이것들이 물리적으로 분산 저장되는 곳이 샤드이다. 

 

  • 샤드

샤드는 인덱스의 전체 데이터를 분산해서 가지고 있는 일종의 부분집합이다. 
샤드로 인해 데이터를 분산 저장하는 방식으로 손쉬운 수평 확장이 가능해진다. (엘라스틱서치의 고가용성이 구현됨)
인덱스를 생성할 때, 엘라스틱서치는 기본적으로 5개의 샤드로 데이터가 분산되도록 생성되지만 개수는 변경이 가능하다.
색인 데이터가 샤드로 분산되는 과정이나 검색 요청이 각 샤드에 분산되어 처리되는 프로세스는 사용자에게는 블랙박스로 제공된다.

 

  • 레플리카

샤드의 복제본. (레플리카는 서로 다른 노드에 존재할 것을 권장한다. )
검색 시 레플리카가 적극적으로 활용된다.

인덱스가 생성될 때 샤드 개수와 레플리카 개수를 설정할 수 있지만, 인덱스 생성 후에는 샤드 개수 변경이 불가하다.
그래서 샤드 개수 설정은 매우 신중히 결정해야한다. 
그에 반해 레플리카 개수는 인덱스 생성 후에도 변경 가능하다.
그래서 운영 중 트래픽 증가에 유연한 대응이 가능하다.

 

  • 세그먼트

문서들은 빠른 검색에 유리하도록 '역색인 구조'(inverted index)로 저장된다.
책 맨뒤에 키워드 마다 찾아볼 수 있도록 '찾아보기'가 inverted index이다. 
(책의 맨 앞의 목차가 index이다. )
샤드 내부에 루씬 라이브러리가 있는데, 이를 이용해 검색 기능이 구현된다.
루씬에 데이터가 색인되면, 데이터는 최소한의 단위인 토큰으로 분리되고, 결국 세그먼트 라는 자료구조로 저장된다.
세그먼트는 '역색인 구조'로 생성되어 있어서 읽기에 최적화된 자료구조이므로 검색 성능에 좋다. 

 

  • 루씬 인덱스

루씬은 다수의 클래스로 구성돼 있는 검색 라이브러리이다. 
핵심 클래스 두 가지는 데이터를 색인하여 세그먼트를 생성하는 IndexWriter와 
색인된 데이터(세그먼트)를 검색하는 IndexSearcher이다.
위의 두 클래스를 가지고 색인과 검색을 동시에 제공하는 루씬 인스턴스를 루씬 인덱스라고 한다.
하나의 샤드는 하나의 루씬 인덱스이다.
물리적으로 분산된 엘라스틱서치 샤드를 논리적 관점에서 하나의 거대한 데이터로 바라보는 것이 엘라스틱서치 인덱스이다. 

 

  • Near Real Time 검색 (근실시간 검색)

커밋포인트 : 여러 세그먼트의 목록 정보를 가지고 있으며, 검색 요청 시 활용된다.
루씬의 IndexSearcher 가 검색 요청 시 커밋 포인트를 이용해 가장 오래된 세그먼트부터 차례로 검색하여 결과를 낸다.
세그먼트가 많아지면 읽기 성능이 떨어지므로, 루씬이 백그라운드로 주기적으로 세그먼트 파일을 병합한다.

 

  • 세그먼트의 불변성 (Immutablity)

세그먼트의 수정을 허용하지 않은 동작 방식을 불변성(Immutablity) 라고 부른다.
역색인 구조로 생성된 세그먼트라는 특징 때문에, 불변성은 장점이 많은 방식이다. 


1) 동시성 문제를 회피할 수 있다.  
다중 스레드 환경에서 lock이 필요 없어진다. (수정이 가능하면 lock이 필요하기 때문) 
2) 시스템 캐시를 적극적으로 활용할 수 있다.
불변성을 보장하지 않을 경우, 데이터가 변경될 때마다 시스템 캐시를 삭제하고 다시 생성해야 하는데, 이는 성능 측면에서 매우 비용이 큰 작업이다.
3) 높은 캐시 적중률.
검색 시 데이터를 항상 메모리에서 읽어올 수 있다.

읽기 연산이 대다수인 검색엔진의 특성상 캐시 성능을 최대한 활용할 수 있다는 장점이 불변성을 채택하는 이유가 된다. 
불변성의 단점은 일부 데이터가 변경된다면 전체 역색인 구조가 다시 만들어져야 한다는 것이다. 

또한 실시간 반영이 어렵다.
변경이 일어날 때마다 세그먼트를 다시 만들지 않고, 추가로 세그먼트를 생성하는 것으로 이러한 단점을 극복한다.
그 이후, 생성된 모든 세그먼트를 읽어서 검색 결과를 제공한다. 

 

  • 루씬을 위한 Flush, Commit, Merge

루씬은 효율적인 색인 작업을 위해 내부적으로 일정 크기의 버퍼를 가지고 있다.
이러한 내부 버퍼를 인메모리버퍼 라고 한다.
버퍼가 없다면, 대량의 데이터가 빠르게 요청될 경우 지연이 발생하여 서비스 장애로 이어질 수 있다.
버퍼를 일종의 큐 처럼 활용한다. 
write()함수를 이용해 커널의 시스템 캐시에 기록하는 쓰기 과정을 수행하고, 일정한 주기에 따라 물리적 디스크 동기화 작업(commit)을 수행한다. 
이러한 인메모리 버퍼 기반의 처리과정을 루씬에서는 Flush 라고 부른다. 
루씬에서는 물리적으로 디스크에 기록을 수행하는 fsync() 함수를 호출하는 작업을 Commit이라고한다. 

루씬은 불변성을 유지하기 위해 세그먼트 단위 검색을 제공하지만,
시간이 흐를수록 세그먼트들의 개수가 늘어나고, 이를 위해 커밋 포인트의 부하도 증가한다.
그래서 다수의 세그먼트를 하나로 합치는 작업이 필요해진다. 
이를 Merge 작업이라고 한다. 
Merge 작업으로 인해 세그먼트 개수가 줄어들면 검색 횟수가 줄어들어 검색 성능이 좋아진다. 
하지만 Merge 작업은 세그먼트를 합치면서 데이터를 삭제하므로,
commit작업을 반드시 동반해야 하므로 매우 비용이 많이 든다. 적절한 주기 설정이 필요하다. 

 

  • 엘라스틱서치를 위한 Refresh, Flush, Optimize API

엘라스틱서치 샤드는 내부에 루씬 인덱스를 가지고 있고, 루씬 인덱스가 가지는 대부분의 기능을 확장해서 API로 제공한다. 

루씬 엘라스틱서치
Flush  Refresh 
Commit  Flush 
Merge  Optimize API 


Refresh : 클러스터에 존재하는 모든 샤드에서 기본적으로 1초마다 한번씩 Refresh 작업이 수행된다.
인덱스를 새로고침해서 새로 추가한 데이터의 검색이 가능해지게 한다. 
_setting API를 이용하면 Refresh 주기를 변경할 수 있다. 
특별한 경우가 아니면 주기를 변경하지 않는 것이 좋다.

Flush : 루씬의 Commit작업을 수행하고, 새로운 Translog를 시작한다는 의미다. 

Translog는 루씬에는 없는 개념. ES가 제공하는 고가용성과 관련이 있다.
Translog는 샤드의 장애복구를 위해 제공되는 특수한 파일이다. 
ES 샤드는 자신의 모든 변경사항을 Translog에 먼저 기록한 후 내부에 존재하는 루씬을 호출한다. 
지속적인 Refresh 작업에 의해 검색은 가능해지지만 아직은 디스크에 물리적 동기화가 되지 않은 상태이므로 주기적으로 루씬 commit을 수행해야 한다.

정책에 의해 루씬 commit이 정상 수행되면, 변경사항이 디스크에 물리적으로 기록이되고,
Translog 파일에서 commit이 정상적으로 일어난 시점까지의 내역이 비로소 삭제된다.
ES에서 기본적으로 5초에 한번씩 Flush 작업이 수행된다. 

Optimize API: 인덱스 최적화를 위해 Optimize API를 제공한다. 이를 forced merge API라고도 한다. (루씬 Merge를 강제로 수행하는 기능)

 

  • Translog 동작 순서

1)데이터가 추가되면 Translog에 기록되고 동시에 인메모리 버퍼에 추가된다.
2) Refresh가 수행되면 인메모리 버퍼에서는 사라지지만 Translog에는 계속 남아있다.
3) 더 많은 데이터가 추가되고 지속적으로 세그먼트가 추가된다. 
4) Translog가 일정 크기 이상 커지면, Flush 작업이 수행된다.
5) 커밋 포인트가 디스크에 Flush 된다. 
6) 시스템 캐시의 내용이 디스크에 Flush 된다.
7) Translog의 기록이 비로소 삭제 된다. 


참고)
커밋포인트 : 여러 세그먼트의 목록 정보를 가지고 있으며, 검색 요청시 활용된다.
루씬의 IndexSearcher 가 검색 요청 시 커밋 포인트를 이용해 가장 오래된 세그먼트 부터 차례로 검색하여 결과를 낸다.

  • 엘라스틱서치 샤드 최적화

샤드 : 실제 서비스가 일어나는 프라이머리 샤드. 실질적인 CRUD 를 제공한다.
레플리카 샤드 : 장애 복구를 위해 존재하지만, 프라이머리 샤드와 동일한 데이터 가지고 있으므로 평상시에 읽기 분산에 활용된다. 

number_of_shards : 프라이머리 샤드의 개수. 
number_of_replicas : 레플리카 세트를 몇개로 구성할지 설정.

5개의 샤드로 분산하고, 1개의 레플리카 세트를 생성하도록 설정한다고 했을 때,
인덱스가 생성되면 5개의 프라이머리 샤드와 5개의 레플리카 샤드가 생성되어, 인덱스 내에 총 10개의 샤드가 존재한다.

샤드는 내부에 독립적인 루씬 라이브러리를 가지고 있고, 루씬은 단일 머신 위에서만 동작하는(Stand Alone) 검색엔진이다.
프라이머리 샤드의 개수를 변경한다는 뜻은 독립적인 루씬 들이 가지고 있는 데이터들을 모두 재조정 하겠다는 뜻이다. 
각 세그먼트는 원칙적으로 변경이 불가능하므로, 프라이머리 샤드의 개수를 변경할 수는 없다.
이 경우, 새로운 인덱스를 생성하고 재색인 하도록 엘라스틱서치에서는 ReIndex API 를 제공한다. 

프라이머리 샤드와 레플리카 샤드는 동일한 세그먼트 생성 과정을 거치게 된다. 
이러한 과정 덕분에 모든 복제본에 일관성이 부여된다.
읽기 분산이 중요한 경우, 색인 성능을 일부 포기하고 레플리카 세트의 수를 늘리는 것이 좋다.
빠른 색인이 중요한 경우, 읽기 분산을 일부 포기하고 레플리카 세트의 수를 줄이는 것이 좋다.

개별 인덱스를 생성할 때 설정 가능한 샤드의 수는 1024개로 제한되어 있다. 

샤드가 많아질 수록 마스터 노드의 부하가 증가한다.
샤드 하나가 물리적으로 50GB가 넘지 않도록 권장한다. 

 

728x90

logstash 를 여러개 실행 하는 것

 

conf 파일을 서로 다른 디렉토리에 두고, logstash.yml의 path.data를 수정해야 한다. 

startup.options 에서 LS_SETTING_DIR 을 conf가 있는 경로로 수정해 준다 

 

보통 실행할 때 $logstash_home_dir/bin/logstash -f temp.conf 로 실행하는데, 

$logstash_home_dir/bin/logstash --path.settings ./temp_conf_0 -f ./temp_conf_0 /temp1.conf

$logstash_home_dir/bin/logstash --path.settings ./temp_conf_1 -f ./temp_conf_1 /temp2.conf 

$logstash_home_dir/bin/logstash --path.settings ./temp_conf_2 -f ./temp_conf_2 /temp3.conf 

 

--path.settings 옆에 conf가 있는 디렉토리 경로를 적어주고, 그 뒤에 conf 파일명을 적어준다.

 

위 처럼 하면 conf 파일 3개가 동시에 수행된다. 

728x90

'일상 > Today I Learn(TIL)' 카테고리의 다른 글

2019-08-13 TIL pandas DataFrame 다루기  (0) 2019.08.13
2019-07-31 TIL Elastic Search  (0) 2019.07.31
2019-07-22 TIL logstash  (0) 2019.07.24
2019-07-21 TIL '쇠막대기' 알고리즘 문제풀이  (0) 2019.07.21
Today I Learn 시작  (0) 2019.07.21

logstash가 실행하는 conf 파일을 작성 

 

temp.conf 로 저장하고

$logstash_home_dir/bin/logstash -f temp.conf 로 실행한다 

 

filter에는 조건을 주는데, mutate 부분은 이상한 컬럼이 들어갈 수 있기 때문에 이를 방지하기 위해 반드시 써줘야 한다. 

input {
        file {
                path => "/home/file.txt"
                start_position => "beginning"
                sincedb_path => "/dev/null"
        }
}

filter {
        csv{
                separator => ","
                columns => ["col1", "col2", "col3"]
        }
        mutate {
                remove_field => ["message", "host", "path", "@timestamp", "@version"]
        }
}

output {
        elasticsearch {
                hosts => "http://address:port"
                index => "index_name"
                document_id => "%{[col1]}"
        }
        stdout {}
}
728x90

백준 10799번 문제(쇠막대기) 를 푸는것을 시작했다.

1시간 생각해도 잘 모르겠어서 백준님의 풀이를 참고했다. 

 

자주 자책하는 성격인지라 문제풀이 할 때 추진력을 잃곤 한다.

 

이를 극복하기 위해, 백준님이 강조하신 내용을 메모해둔다.

 

 

공부하는 방법

1. 스트레스 최대한 덜 받으면서 즐겁게 하기! (가장 중요하다)

2. 알고리즘 문제를 푸는 '방법'을 이해하자. 

  -- 완벽하지 않거나, 일부만 이해했어도 성공!

3. 문제를 풀 때, 2시간 정도만 고민해본다. (나의 경우, 1시간으로 정했다.)

  -- 모르겠으면 정답 소스를 보거나 풀이를 본다 

  -- 막힌다고 풀죽지 않기

4. 위의 2번에서 이해가 잘 가지 않는 부분이 있으면, '질문'한다. 

  -- 백준 슬랙 이용.

  -- '설마 이런것도 질문해도될까?' 고민되는 것도 전부 질문한다.

5. 다시 알고리즘을 이해해보고 문제를 풀어본다. 

  -- 그래도 모르겠으면 풀이를 본다. 

  -- 그래도 모르겠으면 놀러나가거나 다른 문제에 도전한다!

 

* 항상 명심할 점

프로그래밍을 많이 하는 것 보다, 문제 해결에 대한 구체적인 생각을 많이 하자.

728x90

'일상 > Today I Learn(TIL)' 카테고리의 다른 글

2019-08-13 TIL pandas DataFrame 다루기  (0) 2019.08.13
2019-07-31 TIL Elastic Search  (0) 2019.07.31
2019-07-24 TIL logstash 여러개 실행  (0) 2019.07.24
2019-07-22 TIL logstash  (0) 2019.07.24
Today I Learn 시작  (0) 2019.07.21

백준 괄호 문제 풀이  https://www.acmicpc.net/problem/9012

 

9012번: 괄호

문제 괄호 문자열(Parenthesis String, PS)은 두 개의 괄호 기호인 ‘(’ 와 ‘)’ 만으로 구성되어 있는 문자열이다. 그 중에서 괄호의 모양이 바르게 구성된 문자열을 올바른 괄호 문자열(Valid PS, VPS)이라고 부른다. 한 쌍의 괄호 기호로 된 “( )” 문자열은 기본 VPS 이라고 부른다. 만일 x 가 VPS 라면 이것을 하나의 괄호에 넣은 새로운 문자열 “(x)”도 VPS 가 된다. 그리고 두 VPS x 와 y를 접합(conc

www.acmicpc.net

닫는 괄호로 시작하는 경우에 어떻게 할지 예외처리를 안넣어줘서 시간이 좀 걸렸다.

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>

using namespace std;

void check() {
	char stack[50] = {0, };
	int stack_idx = 0;

	char* inputStr = (char*)malloc(sizeof(char) * 50);
	scanf("%s", inputStr);

	int lenSize = strlen(inputStr);

	for (int i = 0; i < lenSize; i++) {
		if (0==i && ')' == inputStr[i]) { //닫는괄호로 시작함.
			printf("NO\n");
			free(inputStr);
			return;
		}
		else {
			if ('(' == inputStr[i]) { //스택에 여는괄호를 넣는다 
				stack[stack_idx] = '(';
				stack_idx++;
			}
			else if (')' == inputStr[i]) { // 닫는괄호 발견.
				if (0 < stack_idx) { // 스택에 여는괄호가 있다면, 하나 삭제.
					stack[stack_idx] = 0;
					stack_idx--;
				}
				else {
					// 여는 괄호 보다, 닫힌 괄호가 더 많음. 불완전.
					printf("NO\n");
					free(inputStr);

					return;
				}
			}
		}

	}

	//printf("stack_idx : %d", &stack_idx);

	if (0 == stack_idx) {
		printf("YES\n");

	}
	else {
		printf("NO\n");
	}

	free(inputStr);
	return;

}

int main() {

	// 반복 횟수 입력 받기
	int repeat = 0;

	scanf("%d", &repeat);

	while (repeat) {
		check();
		repeat--;
	}

	return 0;
}

 

 

728x90

'알고리즘 > 백준' 카테고리의 다른 글

카드 구매하기 백준 11052  (0) 2020.08.13
2xn 타일링2 백준 11727번  (0) 2020.08.12
2xn 타일링 백준 11726번  (0) 2020.08.12
분산처리 백준 1009번 c++  (0) 2020.08.12
스택 백준 10828번  (0) 2020.08.12

+ Recent posts