728x90
반응형

운영체제의 필요성과 목적

- 한정된 자원(limited source)과 사용자 사이의 경쟁을 조율하기 위한 운영자(운영체제)의 정책(운영체제가 수행하는 알고리즘)이 필요하다

- 컴퓨터에서의 자원과 경쟁 : 일반적으로 하드웨어 자원을 사용하고자하는 프로세스가 자원의 한도를 넘어간다. 

-> 컴퓨터 속에서는 항상 여러 프로그램이 한정된 자원을 서로 독차지하려고 경쟁

- 가장 적합한 알고리즘을 수행하는 것이 중요하다 -> 적합한 알고리즘이란 어떤 것을 갖춘 것일까?

- 효율성(efficiency)과 편의성(convenience)을 갖춘 알고리즘(ex> 스케쥴링 알고리즘)

- 효율성 : 하드웨어를 얼마만큼 쉬지않고 사용하게 했는지에 관한 지표(프로세스 여러개 돌리는 경우)

- 편의성 : 사용자가 얼마만큼 불편함없이 사용할 수 있는지에 관한 지표(프로세스 하나만 돌리는 경우)

- 편의성을 높이려면 프로그램 하나가 하드웨어를 독점해서 사용하면 제일 극대화되는데 이렇게 되면 효율성이 매우 떨어진다는 점.

- 효율성을 높이려면 동시에 여러개를 실행시키면 되는데 이렇게 되면 편의성이 떨어진다.

- 따라서 효율성과 편의성 최적점 유지를 위해 운영체제가 필요하다

- 일관성 : 다양한 입출력 장치의 운영 및 제어의 일관성. 디바이스 드라이브를 표준에 맞도록 개발할것을 요구. 운영체제는 이를 토대로 장치 운영. 

- 운영체제의 목적 : 편의성(사용자 관점) + 효율성(자원 활용) + 일관성(다양한 입출력 장치의 운영 및 제어)

초기 시스템

- 프로그램을 기계어로 작성 : 한줄 한줄을 카드 천공기에 펀칭해서 기록 (예를 들어 100줄-> 100장 필요)

- 자기테이프나 카드천공기로 카드에 기록

- 이렇게 기록해서 프로그래머가 Sign Up Sheet 원하는 시간을 예약해서 시간이 되면 카드덱에 자신이 펀치카드 묶음을 적재하고 컴퓨터가 읽게함

- 콘솔을 이용해서 프로그램 수행/디버깅. 라이브러리도 카드덱 형태

- 자기 시간이 되면 자기 혼자 컴퓨터 독점 -> Sign Up Sheet에 비는 시간 생기니까 효율성이 떨어진다

- Tape나 Punch-Card로 프로그램 적재하니까 준비 시간 과다

- 편의성은 좋은데 효율성이 떨어짐 -> 하드웨어가 비쌀 시기라 효율성 높이는데 주력했음

초기 일괄처리 시스템

- 아이디어 : 주컴퓨터(계속 작업)와 위성 컴퓨터(프로그램 적재, 결과물 출력) 분리

- but> operation에 대한 의존도가 높아서 다음 단계인 일괄처리 시스템으로 발전

- 운영자(operator)를 고용하여 사용자의 직업을 전문적으로 대행

- 사용자들이 요구하는 비슷한 작업들을 함께 묶어서 배치(batch)로 처리

- 배치가 적당한 규모가 되면 카드리더기에 적재하여 자기 테이프로 저장함

- 그러면 위성컴퓨터에서 떼어서 주컴퓨터로 탑재시켜줌(오프라인) -> 주컴퓨터는 자기테이프를 읽어서 그 안의 프로그램을 수행시킴

- 그러는동안 operator하는 위성 컴퓨터 이용해서 다음 배치를 자기테이프에 기록하는 작업을 한다.

- 입력은 이렇게 진행하고 출력도 마찬가지이다.

- 배치는 별도의 오프라인 카드리더나 테이프에 수록되고, 처리 결과도 별도의 오프라인 테이프를 통해 프린터로 출력됨

-> 주컴퓨터는 operator가 자기테이프를 걸어주기만 하면 쉬지않고 작업할 수 있다. (초기 시스템의 효율성 크게 개선)

-> but> 배치는 operator가 하기때문에 operator는 사람이기 때문에 완벽하지 않다.

일괄처리시스템

- 초기 일괄처리 시스템에서 operator를 자동화시키는데 목적을 둠.

- 이를 위해 고안된 것이 1. 채널 2. 버퍼 3. 인터럽트

- operator의 작업을 없애려면 카드리더기나 카드덱(또는 프린터) 입출력장치가 주컴퓨터와 직접적으로 인터페이스 되어야 하지 않겠냐?

채널 : operator가 프로그램과 데이터를 자기 테이프에 넣어서 주컴퓨터에게 수동으로 장착시키는 작업을 자동화 한것이 채널이다.

- 입출력장치가 CPU에 간섭없이 독립적으로 메모리의 특정부분에 직접 자료를 전송하도록 해주는 회로

- 이를 위해 명령어, 레지스터, 제어회로, 제어장치 로 이루어져 있다

- 채널에 의해서 CPU와 입출력장치가 병렬적 수행이 가능하게 되었다

=> CPU 간섭없이 입출력장치가 버퍼로가는 메모리 상의 일정 부분을 접근하도록 해주었다.

- but> CPU와 채널간의 전혀 간섭이 없을 수는 없다. CPU도 버퍼접근하고 채널도 버퍼접근하기 때문

(CPU와 함께 메모리를 공유)

즉, 메모리를 사이에 두고 CPU와 입출력장치가 서로 경쟁을 벌일 수 있다 (-> 사이클스틸링이라는 것으로 해결)

- CPU로부터 명령을 받아 CPU와 독립적으로 입출력 실행(단, 메모리 사이클 경쟁 제어 필요 -> DMA)

- DMA : 주변장치들이 메모리에 직접 접근하여 읽거나 쓸 수 있도록 하는 기능(CPU의 개입없이)

--> CPU가 해야할 주변장치와의 데이터 전송을 대신 해줘서 CPU 효율을 늘릴 수 있다

버퍼 : 채널이 입출력을 위해서 사용하는 메모리 상의 약속된 장소이자 CPU가 입출력 정보를 접근하는 장소이다. 

- 버퍼가 있기 때문에 채널과 CPU가 서로 어긋나지 않고 자료를 공유하면서도 서로 간섭없이 각자의 역할을 수행

(CPU와 채널 입출력의 병렬 수행을 위하여 데이터 버퍼를 사용)

- 연산하는 동안 읽거나, 쓰는 것이 가능하게 되어 입출력 대기시간을 없앰

인터럽트 : 채널의 입출력과 CPU의 작업이 전혀 상관없이 작동하지는 않는다

- 채널을 통한 입출력은 CPU의 명령을 받아 실행해야 한다

- CPU는 입출력 명령이 끝날때까지 자신의 작업을 하더라도 입출력이 끝났는지는 통보받을 수 있어야 자료공유가 원할해진다 -> 이를 위해 인터럽트가 필요하다.

- 그럼 CPU는 인터럽트를 받으면 어떤 작업을 수행해야 할까? -> 해당 인터럽트에 대한 조치를 취하는데 입출력장치의 종류에 따라 매우 다양하다. -> 조치 또한 프로그램으로 만들어져서 메모리 특정부분에 탑재 되어야 했다 (ISR)

- 인터럽트는 사용자 프로그램이 아니라 하드웨어에 의하여 자동으로 메모리 특정 부분에 있는 함수(ISR, Interrupt Service Routine)를 호출하는 개념이다.

- 입출력의 완료와 예외동작 처리( ex> 파일종료, 테이프 끝, 패리티 오류 등)도 ISR로 프로그래밍 되어 있다.

- 채널을 통한 입출력 버퍼링을 CPU와는 독립적으로 수행토록 하는 핵심 수단

- cf> 트랩 : 인터럽트와 유사한데 부동소수점 연산 언더플로우, 오버플로우, 소프트웨어 인터럽트(소프트웨어적 오류)

트랩은 커널공간과 사용자공간을 나누어서 접근할 수 있는 권한설정에서 매우 중요한 역할을 한다.

 

-> CPU는 CPU나름 입출력장치는 입출력장치 나름대로 데이터를 출력하고 메모리 어느 곳에 데이터를 얹어놓는데 이곳이 버퍼이다. 양쪽이 분리되어 동작하고 서로 소통은 CPU를 통해 진행한다.

- 문제는 주컴퓨터 CPU가 부하가 걸린다(operator가 있을땐 나눌 수 있었는데 operator를 없애다 보니까 CPU가 과부하)

-> 해결 : 입출력장치와 CPU가 각자의 간섭없이 작업을 하도록 하고, 그동안 입출력장치가 컴퓨터 메모리상의 약속된 장소를 직접 접근하면서 입출력을 끝내도록 하고, 그 작업이 끝나면 CPU에 알리도록 해서 CPU가 다음 입출력 작업을 지시하도록 한다.

 

일괄처리시스템에서 모니터의 태동 : operator 자동화를 위해서는 메모리에 상주하는 프로그램이 필요하다

-> operator 대신 프로그램이 메모리에 올라가 있어야 되기 때문( ex> ISR, 적재기, JOB Sequencer, 제어카드 번역기)

 

상주모니터(Resident Monitor)

- 컴퓨터가 시동되는 시점부터 메모리에 탑재되어서 영구적으로 상주해야되는 것들

- 인터럽트 처리기 또는 입출력 관리자를 메모리에 영구적으로 상주시켜야 할 필요성 대두

- 작업 제어 명령어, 적재기, 작업 순서 제어기를 상주시켜 컴퓨터의 운영을 좀더 자동화 시킴

 

보호 이슈 >>

- 모니터가 메모리에 상주하는데 메모리에는 모니터도 있지만 채널을 통해서 버퍼에 들어오는 것이 프로그램이 탑재되어 들어올 수도 있다.

-> 다른 프로그램이 메모리 한 부분에 위치하게 되어서 CPU에 의해서 수행될 수도 있다. (ex> 사용자 프로그램들)

-> 이 프로그램을 수행하다가 모니터의 영역을 침범하는 경우가 생긴다 (즉, 덮어쓰는 경우가 생겨서 상주 모니터 보호의 필요성 대두된다)

 특히 입출력할 때 자주 발생해서 이를 방지하기 위해 모든 사용자 프로그램은 입출력을 직접 하지 않고 반드시 모니터가 제공하는 입출력 함수를 호출해서 입출력하도록 했다 (-> 시스템 콜의 태동)  ex> fork() 함수

(시스템 콜 : 커널 내의 함수를 응용 프로그램이 불러 쓰는 것)

-> 미리 작성된 테이블에 기록된 메모리 접근 허용치(사용자 프로그램이 접근할 수 있는 메모리 영역 허용치) 참조하여 각 연산 수행 시 메모리 접근 범위를 제한한다. 

 

일괄처리시스템의 장점

- 초기 일괄처리 시스템에 비하여 효율성 개선됨(효율성 높이는데 큰역할)

- 하나의 작업이 CPU를 독점하므로 해당 작업으로 볼 때는 처리 속도가 가장 빠르다 (프로그램이 자원 독점)

- 사용자와의 대화가 필요하지 않은 CPU-bound 응용 프로그램 수행에 적합하다 (수치 계산, 대용량 데이터 처리 등)

단점

- 사용자와의 대화가 필요한 요구들이 많을때(ex> 편집기 ) 이것을 수행하기에는 부족하다

- 일괄 처리 시스템은 한 작업, 한 작업을 순차적으로 처리 -> 한 프로그램이 입출력을 위해 소모한 시간은 다음 프로그램에게는 기다리는 시간(즉, 전체 처리량 저하)

--> 그렇다면 여러 프로그램을 동시에 실행시키면??

 

다중 프로그래밍(Multiprogramming)

다중 프로그래밍은 일괄처리시스템과 달리 프로그램을 번갈아 수행한다

- 프로그램을 수행하다보면 어느 순간 입출력이 일어남(키보드 입력을 기다리거나 출력이 끝나기를 기다리는 상태에 도달)

-> 입력이 들어오기까지 마냥 기다리는 것이 아니라 입력이 들어오면 interrupt를 걸도록 해놓고 그 사이 다른 프로그램 선택해 수행
(이걸 모든 프로그램에 적용하면 번갈아가며 수행시킬 수 있게 된다)

- 한 시점에 여러 프로그램을 사용자 영역에 탑재

 -- 시스템에 들어오는 모든 작업은 일단 작업 풀(디스크 사용)에 적재됨

 --작업풀 내의 작업은 운영체제의 정책에 따라 선택되어 메모리에 탑재

- 탑재된 작업 중 하나를 선택하여 실행한다

- 한 프로그램이 입출력을 하는 동안 다른 프로그램을 선정하여 CPU가 실행한다(이것이 스케쥴링, 어떤것 선정이 좋을지 정책 필요)

- 스케쥴링이 언제 일어나냐 -> 다중 프로그래밍인 경우 수행중이던 프로그램에서 입출력이 일어날 경우에만 스케쥴링이 일어난다.

(- 시분할 시스템에서도 스케쥴링 일어나는데 차이 구분하면??)

- 만약 program2에 문제가 있어 무한 loop 돈다(program1은 cpu 받기를 기다리고 있다) -> 스케쥴링은 입출력 변할때만 이루어지니까 program2가 무한루프를 돌면 입출력을 하는 순간은 오지 않는다. 즉, 입출력 요구하는 상황이 벌어지지 않는다 -> 스케쥴링도 일어나지 않는다 -> program1 영원히 대기

- 그래서 다중 프로그래밍인 경우 프로그램 간섭이 일어날 수 있다

1. 스케쥴링은 입출력이 일어났을때만 된다 2. 프로그램 간의 간섭이 일어날 수 있다

-> 대부분 프로그램의 실행 시간에서 CPU의 사용 시간은 극히 일부분이고 나머지는 입출력 시간이다.

-> N개의 프로그램이 실행된 시간이 각각 t1, t2, ... ,tn이라 할 때,

   - 일괄처리 또는 uniprogramming : t1+t2+t3+... +tN

   - 다중프로그래밍인 경우 대략 : max(t1,t2,,,,tN)

- 한 프로세스의 입출력 시에 다른 프로세스를 처리할 수 있게 되므로, CPU가 항상 일을 하고 있게 됨

- 또한, 디스크를 이용한 BufferingSpooling으로 입출력과 CPU수행의 중복 정도를 높일 수 있게됨

  - Input Spooling은 Job Scheduling에 사용

  - Output Spooling은 산발적인 프린트 출력을 모아서 프로세스가 끝난 후에 출력

- 새롭게 대두되는 이슈

   - Job Scheduling : 최적의 스케쥴링 방법

   - 메모리 경영 - 여러 작업이 메모리 상에 존재, 한정된 메모리 공간에 n개의 프로그램 탑재해야 되기 때문에 어떤 것들을 탑재하느냐에 대한 알고리즘

 

- Buffering과 SPOOLing (Simultaneous Peripherial Operations On-Line)

  - Buffering은 메모리 버퍼를 이용하여 I/O와 CPU의 속도 차를 해소하여 독립된 동작을 허용

  - Spooling은 하나의 순차적 처리 장치(예: 프린터)를 여러 프로세스(프로그램)가 디스크를 활용하여 동시에 공유할 수 있도록 하는 기능 제공 (디스크 활용이 포인트)

- 왜? : 디스크는 속도가 빨라서 랜덤하게 접근이 가능하기 때문에 각 프로그램이 프린터를 동시에 접근하는  효과. 

각 프로세스는 프린터에 출력한 줄 아는데 알고보면 디스크에다 출력을 해놓은 것. 디스크는 속도가 빠르니까 여러 출력들을 빠르게 저장해 놓을 수 있다.

- 하나의 순차적 처리장치(프린터)를 여러 프로세스가 디스크를 활용하여 동시 공유 기능 제공

- 스풀링을 사용한다면 각 프로그램의 수행이 끝나기 전까지는 잠시 각 프로그램마다 디스크 상의 영역을 마련하는 것 

--> 그곳에 저장

- 그런 후 프로그램이 종료되면 해당 영역의 출력 내용을 프린터를 통하여 출력 -> 프로그램 단위별로 묶어서 순차적으로 출력

 

728x90
반응형

'CS > 운영체제' 카테고리의 다른 글

[3] 컴퓨터 구조와 OS 연계  (0) 2022.03.14
[2] 시분할 시스템, 실시간 시스템  (0) 2022.03.09
프로세스의 연산  (0) 2020.11.03
프로세스 제어블록(Process Control Block)  (0) 2020.10.29
프로세스의 개요  (0) 2020.10.29
728x90
반응형

파이썬은 map, filter와 같은 함수형 기능을 지원하며 다음과 같은 람다 표현식도 지원한다.

list(map(lambda x:x+10,[1,2,3]))
# [11,12,13]

 

리스트 컴프리헨션

리스트 컴프리헨션이란 기존 리스트를 기반으로 새로운 리스트를 만들어내는 구문으로, 파이썬 2.0부터 지원되었으며 파이썬의 대표적인 특징이다. 

람다 표현식에 map이나 filter를 섞어서 사용하는 것에 비해 가독성이 훨씬 높다.

 

Ex> 홀수인 경우 2를 곱해 출력하라는 리스트 컴프리헨션

[n*2 for n in range(1,10+1) if n%2 == 1]
# [2, 6, 10, 14, 18]

만약에 리스트 컴프리헨션을 사용하지 않는다면 다음과 같이 작성해야 한다.

a=[]
for n in range(1,10+1):
    if n%2 == 1:
        a.append(n*2)

 

파이썬은 리스트만 가능한것이 아니라 딕셔너리도 가능하다.

a={}
for key,value in original.items():
    a[key] = value
# 위의 코드를 아래와 같이 바꿀 수 있다
a={key:value for key,value in original.items()}

 

제너레이터

제너레이터는 루프의 반복 동작을 제어할 수 있는 루틴 형태를 말한다. 예를 들어 숫자 1억 개를 만들어내 계산하는 프로그램을 작성한다고 하였을때 이 경우 제너레이터가 없으면 메모리 어딘가에 만들어낸 숫자 1억 개를 보관하고 있어야 한다. 그러나 제너레이터를 이용하면, 단순히 제너레이터만 생성해두고 필요할 때 언제든 숫자를 만들어낼 수 있다. 

기존의 함수는 return 구문을 맞닥뜨리면 값을 리턴하고 모든 함수의 동작을 종료한다. 그러나 yield는 제너레이터가 여기까지 실행 중이던 값을 내보낸다는 의미로, 중간값을 리턴한 다음 함수는 종료되지 않고 계속해서 맨 끝에 도달할 때까지 실행된다. 

def get_natural_number():
    n=0
    while True:
        n+=1
        yield n

이 경우 함수의 리턴 값은 다음과 같이 제너레이터가 된다.

 

만약 다음 값을 생성하려면 next()로 추출하면 된다. 예를 들어 100개의 값을 생성하고 싶다면 다음과 같이 100번 동안 next()를 수행하면 된다.

g=get_natural_number()
for _ in range(0,100):
	print(next(g))

 

range()

제너레이터의 방식을 활용하는 대표적인 함수로 range() 가 있다. 주로 for 문에서 쓰이는 range() 함수의 쓰임은 다음과 같다. 

list(range(5))

# [0,1,2,3,4]

 

range()는 range 클래스를 리턴하며, for 문에서 사용할 경우 내부적으로는 제너레이터의 next()를 호출하듯 매번 다음 숫자를 생성해내게 된다. 

 

enumerate()

enumerate()는 '열거한다'는 뜻의 함수로, 순서가 있는 자료형(list,set,tuple)을 인덱스를 포함한 enumerate 객체로 리턴한다. 

a=[1,2,3,2,45,2,5]
print(list(enumerate(a)))
# [(0, 1), (1, 2), (2, 3), (3, 2), (4, 45), (5, 2), (6, 5)]

이처럼 list()로 결과를 추루할 수 있는데, 인덱스를 자동으로 부여해주기 때문에 매우 편리하게 사용할 수 있다. 

for i,v in enumerate(a):
	print(i,v)
728x90
반응형

'알고리즘 > 파이썬 알고리즘' 카테고리의 다른 글

[알고리즘] 에어컨  (0) 2023.09.11
[TIL] Python Join 함수  (0) 2022.07.13
모듈, standard library  (0) 2021.05.29
사전  (0) 2021.05.28
옵셔널 파라미터 (optional parameter)  (0) 2021.05.20
728x90
반응형

https://reactjs.org/docs/hooks-rules.html

 

Rules of Hooks – React

A JavaScript library for building user interfaces

reactjs.org

여기 문서를 살펴보면

Only Call Hooks at the Top level

Don't call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. 

즉, hook은 문서의 최상단에 어떠한 값이 return 되기 전에 정의 되어야 한다. hook을 사용하기 전에 조건문으로 return 하는 코드가 있으면 에러가 발생하게 된다. 

Hook을 사용하는 코드를 return이 있는 코드 위로 올려서 실행해주면 된다. 

728x90
반응형
728x90
반응형

npm 설치를 하는데 이런 오류가 나왔었다. 

github 작업할 때 @react-native-firebase/auth는 node-module에 있었는데 @react-native-firebase/storage를 설치해서 사용하려고 하니까 설치가 안되는 오류였다. 

오류메시지는 Conflicting peer dependecy 와 Could not resolve dependency 였는데 @react-native-firebase안에 이미 auth가 있고 storage가 뭔가 이미 설치된거랑 안맞아서 오류가 생기는 느낌..?(영어 그대로 해석해봤을때..)

https://iancoding.tistory.com/154

 

[오류해결] npm install 설치시 npm ERR! code ERESOLVE

npm install react-paypal-express-checkout --save npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree paypal 이용하려고 설치하려고 하자 위와 같이 오류가 났다.  해결방법 npm i..

iancoding.tistory.com

다음을 참고해서 해결하였다.

npm install @react-native-firebase/firestore --legacy-peer-deps 

뒤에 --legacy-peer-deps를 사용하여 해결하였다.

 

https://velog.io/@yonyas/Fix-the-upstream-dependency-conflict-installing-NPM-packages-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0%EA%B8%B0

 

npm install `--force` and `--legacy-peer-deps` 차이점

참고 https://stackoverflow.com/questions/66020820/npm-when-to-use-force-and-legacy-peer-deps

velog.io

다음을 참고하니까 npm이 버젼이 새로워지면서 원래는 peer dependecies가 있으면 경고만 뜨고 설치는 되었는데 npm7버전은 설치가 막힌다고 한다. 

그래서 --force를 사용하던지 --legacy-peer-deps를 사용하면 충돌을 무시한다고 한다.

728x90
반응형
728x90
반응형

useState에 대해 간단한 활용법에 대해서만 배우고서는 사용하려니까 object 특정 값만 변경할때 문제가 생겼다.

도움을 받아서 해결하였다.

const [keyword, setKeyword] = useState([
    /label : 키워드 이름 select: 선택되었는지 여부/
    {key: index++, label: '랜덤', select: false},
    {key: index++, label: '자연', select: true},
    {key: index++, label: '건축', select: true},
    {key: index++, label: '예술', select: true},
    {key: index++, label: '뷰티', select: true},
    {key: index++, label: '교육', select: true},
    {key: index++, label: '테크', select: true},
  ]);
  const changeKeyword = e => {
    console.log(keyword[e.key]);
    setKeyword(prevState => ({
      ...prevState,
      [keyword[e.key].select]: true,
    }));
  };

처음에 하고 싶었던 것은 useState Hook을 이용해서 changeKeyword함수를 만들어 해당 select 값을 true로 바꾸어주고 싶었다.

 

아래는 수정 코드이다.

const [keyword, setKeyword] = useState([
    /*label : 키워드 이름 select: 선택되었는지 여부*/
    {key: index++, label: '랜덤', select: true},
    {key: index++, label: '자연', select: true},
    {key: index++, label: '건축', select: true},
    {key: index++, label: '예술', select: true},
    {key: index++, label: '뷰티', select: true},
    {key: index++, label: '교육', select: true},
    {key: index++, label: '테크', select: true},
  ]);
  /* 키워드 추가 */
  const changeKeyword = e => {
    let newKeywords = keyword.map(k => {
      if (k.key === e.key) {
        return {
          ...k,
          select: true,
        };
      } else {
        return k;
      }
    });
    setKeyword(newKeywords);
  };

자바스크립트 문법에 대해서 부족했었던것 같다.

 

위의 문법을 그래로 사용하여 키워드를 제거하는 함수도 만들어 주었다.

/* 키워드 삭제 */
  const remove = e => {
    console.log(e);
    let newKeywords = keyword.map(k => {
      if (k.label === e) {
        return {
          ...k,
          select: false,
        };
      } else {
        return k;
      }
    });
    setKeyword(newKeywords);
  };
728x90
반응형
728x90
반응형

https://www.acmicpc.net/problem/2346

 

2346번: 풍선 터뜨리기

1번부터 N번까지 N개의 풍선이 원형으로 놓여 있고. i번 풍선의 오른쪽에는 i+1번 풍선이 있고, 왼쪽에는 i-1번 풍선이 있다. 단, 1번 풍선의 왼쪽에 N번 풍선이 있고, N번 풍선의 오른쪽에 1번 풍선

www.acmicpc.net

[나의 문제 분석]

요세푸스 문제(https://jobdong7757.tistory.com/113?category=916339)와 비슷했던것 같다. 근데 문제는 여기서 s 배열에 음수가 존재하면 오른쪽이 아닌 왼쪽으로 원을 둘러서 가야된다는 사실이다. 이 부분때문에 헷갈려서 헤매었다. 그리고 처음 시작점이 여기서는 0으로 지정되어있다. 그래서 한번 삭제를 하고 반복문을 돌려주어야 한다. 

[나의 해결 방안]

n=int(input())
s=list(map(int,input().split()))
start=0
index=[x for x in range(1,n+1)]
answer=[]
temp = s.pop(start)
answer.append(index.pop(start))

while s:
    if temp<0:
        start = (start+temp)%len(s)
    else:
        start=(start+temp-1)%len(s)
    temp = s.pop(start)
    answer.append(index.pop(start))
for i in answer:
    print(i,end=' ')

 

n과 s는 주어진 입력이고 start에는 다음 지점을 저장해주려고 하였다. index는 정답에 저장하기 위해서(정답은 0 index를 1로 바꿔서 출력해주어야하기 때문)에 사용하였다. temp에는 s배열의 값을 temp에 저장해주었다.

while문을 하기 전에 이 문제는 시작점이 0으로 정해져있기 때문에 start=0으로 초기화 하고 temp는 s의 start값의 index를 pop해서 저장해준다. 

while문을 이제 시작할때 temp의 값이 음수일때가 문제인데 이 문제를 python의 나머지 기호(%)를 잘몰랐던 나의 무지였었다. 

https://seokdev.site/204 이 사이트에서 다시 공부하고 왔다.. python에서는 c언어의 %와 달리 -1%10을 하면 9가 나오게 된다. 즉, A%B 가 있으면, A에다가 B를 계속 더하면서 처음으로 양수가 되었을 때 B로 나눠 나머지를 준다.

예를 들어 -1%10이면 -1+10=9, 9%10=9 이런식으로 나오는 것이다.

이 문제에서 temp가 음수이면 그냥 start에 temp를 더해서 s의 길이로 나누면 왼쪽으로 -temp만큼 가는것처럼 보이게 되는 것이다. 그래서 temp<0일 때를 처리해 줄 수 있다.

[다른 사람 풀이]

위의 풀이가 temp<0을 처리하기 제일 용이했었는데 그것 말고도 deque에 temp<0을 처리해줄 수 있는 방법도 있었다.

 

enumerate는 반복문 사용 시 몇 번째 반복문인지 확인이 필요할 때 사용할 수 있다. 이거는 index 번호와 collection의 원소를 tuple 형태로 반환한다. 

예를 들어 이런식이다.

t = [1, 5, 7, 33, 39, 52]
for p in enumerate(t):
	print(p)

(0, 1)
(1, 5)
(2, 7)
(3, 33)
(4, 39)
(5, 52)

그리고 deque의 rotate() 메서드.

deque.rotate(num)을 하면 deque를 num만큼 회전한다.(양수면 오른쪽, 음수면 왼쪽)

# Contain 1, 2, 3, 4, 5 in deq
deq = deque([1, 2, 3, 4, 5])

deq.rotate(1)
print(deq)
# deque([5, 1, 2, 3, 4])

deq.rotate(-1)
print(deq)
# deque([1, 2, 3, 4, 5])

그래서 위 문제는 다음과 같이 풀 수 있다. (참고: https://par3k.tistory.com/215)

from collections import deque
n = int(input())
q = deque(enumerate(map(int,input().split())))
ans=[]

while q:
    idx,num = q.popleft()
    ans.append(idx+1)
    if num>0:
        q.rotate(-(num-1))
    elif num<0:
        q.rotate(-num)
print(' '.join(map(str,ans)))

아까처럼 temp>0일때는 rotate를 시계반대방향으로(왼쪽)하면 되니까 q.rotate(-(num-1))을 하였다. num-1을 한것은 해당하는 풍선은 터뜨려야 하기 때문에. 

그리고 num<0이면 q.rotate(-num)을 하면 된다. -num은 양수이므로 오른쪽(시계방향으로) rotate된다.

728x90
반응형
728x90
반응형

https://www.acmicpc.net/problem/10799

 

10799번: 쇠막대기

여러 개의 쇠막대기를 레이저로 절단하려고 한다. 효율적인 작업을 위해서 쇠막대기를 아래에서 위로 겹쳐 놓고, 레이저를 위에서 수직으로 발사하여 쇠막대기들을 자른다. 쇠막대기와 레이저

www.acmicpc.net

[나의 문제 분석]

문제가 복잡하게 적혀 있는데 괄호로 표현해주어서 이해하기 쉬웠다. 처음에 생각한것은 쇠막대기와 레이저의 출발과 끝을 따로 배열로 저장해서 하나씩 볼려고 하였다. 물론 직관적으로 바로 풀었는데 O(n^2)이라서 문제 맞추면 더 좋은 풀이 생각해야지 했더니만 역시.. 시간초과가 뜨고 말았다.

[처음 풀이] 예시들은 제대로 출력되지만 더 빠른 방법이 정답일것 같았다.

s=input()
pipe=[]
raser=[]
stack=[]
answer=0
for i in range(len(s)):
    if s[i]=='(':
        stack.append(i)
    elif s[i]==')':
        if s[i-1]=='(':
            stack.pop()
            raser.append((i-1,i))
        else:
            pipe.append((stack.pop(),i))
for i in pipe:
    count=0
    for j in raser:
        if i[0]<j[0] and i[1]>j[0]:
            count+=1
    answer+=count+1
print(answer)

 

괄호는 '(', ')' 두개밖에 없고 '('인 경우는 쇠파이프 1개가 새로 시작하거나, 레이저인 경우밖에 없고, ')'인 경우는 쇠파이프 1개가 끝나거나 레이저인 경우밖에 없으므로 결국 input받은걸 하나씩 분석해가면 O(n)안에 문제를 해결할 수 있다.

 

[나의 해결 방안]

'('인 경우에는 stack안에 집어넣고 ')'인 경우 앞에 것이 바로 '('이면 레이저이므로 stack에 넣은 '('를 빼내준다. 그리고 레이저로 자르면 되는데 이때는 stack의 크기만큼 나온다.

그리고 ')'를 만났는데 그 앞에게 ')'인 경우는 막대기 하나가 끝난경우로 보면 되므로 stack에서 하나 pop해주고 정답을 +1해준다.

s=input()
stack=[]
answer=0
# '('가 들어오는 경우 -> 쇠파이프 1개가 새로 시작하거나, 레이저인 경우
# ')'가 들어오는 경우 -> 쇠파이프 1개가 끝나거나, 레이저인 경우
for i in range(len(s)):
    if s[i]=='(':
        stack.append(i)
    elif s[i]==')':
        if s[i-1]=='(':
            stack.pop()
            answer+=len(stack)
        elif s[i-1]==')':
            stack.pop()
            answer+=1
print(answer)

[다른 사람 풀이]

거의 비슷한것 같다.

728x90
반응형
728x90
반응형

https://www.acmicpc.net/problem/1935

 

1935번: 후위 표기식2

첫째 줄에 피연산자의 개수(1 ≤ N ≤ 26) 가 주어진다. 그리고 둘째 줄에는 후위 표기식이 주어진다. (여기서 피연산자는 A~Z의 영대문자이며, A부터 순서대로 N개의 영대문자만이 사용되며, 길이

www.acmicpc.net

[나의 문제 분석]

제일 먼저 생각한것은 stack구조였다. 알파벳이 하나씩 나오다가 연산자를 맞닥뜨리면 그때 연산자와 맨 마지막에 들어간 알파벳 2개를 서로 연산해주면 된다고 생각했다. 로직은 간단했는데 내가 부족한 스킬이 몇개가 있었다. 첫번째는 알파벳을 입력받은 배열의 숫자로 어떻게 바꾸어주냐에 관련한 것이였고, 두번째는 정답을 출력할때 소수 2번째까지 출력해주어야하는데 기억이 안나서 살짝 헤매었다. 

1. 알파벳 입력을 숫자로 바꾸어주는것은 일반 nums라는 배열에 0을 저장해두고 알파벳을 확인할때 해당 nums의 index에 맞는 숫자를 출력해주면 된다. 

    if a.isupper():
        s.append(nums[ord(a)-ord('A')])

이 코드처럼 a가 대문자임을 if문으로 확인하고, nums배열에서 A가 0번째, B가 1번째,... 이런식으로 가니까 만약 A라면 ord(a) - ord('A')는 0이되므로 nums의 첫번째에 해당하는 것이 나오게 된다. B,C,D도 마찬가지이다.

2. 소수 2번째까지 출력해주는 방법은 파이썬에서 여러가지가 있다. 

- 내가 사용한것은 format 서식 지정으로 소수점을 관리하였다. 

print("{:.nf}".format(number)) 로 number의 소수점 n+1번째 자릿수에서 반올림해서 소수점 n번째 자릿수까지 출력함으로써 소수점을 관리할 수 있다.

- f-string에서 소수점 관리

: print(f"{number:.nf}")로 number의 소수점 n+1번째 자릿수에서 반올림해서 소수점 n번째 자릿수까지 출력한다.

- %.?f

print('%.nf' %number)로 number의 소수점 n+1번째 자릿수에서 반올림해서 소수점 n번째 자릿수까지 출력한다.

[나의 해결 방안]

n = int(input())
sen = input()
s=[]
nums=[0]*n
for i in range(n):
    nums[i]=int(input())
for a in sen:
    if a.isupper():
        s.append(nums[ord(a)-ord('A')])
    elif a=='+':
        one = s.pop()
        two = s.pop()
        s.append(two+one)
    elif a=='-':
        one = s.pop()
        two = s.pop()
        s.append(two-one)
    elif a=='*':
        one = s.pop()
        two = s.pop()
        s.append(two*one)
    elif a=='/':
        one = s.pop()
        two = s.pop()
        s.append(two/one)
print("{:.2f}".format(s[0]))

[다른 사람 풀이]

조금 어지럽게 푼 느낌이 있어서 다른 사람들 풀이도 찾아보았다. 

https://velog.io/@dailyhyun/BOJ%EB%B0%B1%EC%A4%80-1935.-%ED%9B%84%EC%9C%84%ED%91%9C%EA%B8%B0%EC%8B%9D2

 

[BOJ/백준] 1935. 후위표기식2 (python)

https://www.acmicpc.net/problem/1935후위 표기식에 맞게 피연산자에 해당하는 값을 계산하면 되는 문제​피연산자가 나오면 stack에 push(append) 하고, 연산자가 나오면 pop 하면 된다.단, stack에서 피연산자

velog.io

기본적인 로직은 비슷하였고 대문자임을 판단하는 방식을 

if 'A' <= i <= 'Z': 로 하였다. 나머지는 비슷한것 같다.

728x90
반응형

+ Recent posts