import sys
from collections import deque

def input():
    return sys.stdin.readline().rstrip()
A = list(input())

B = list(input())
N = len(A)

A.sort()
B.sort()
A = deque(A[:(N+1)//2])
B = deque(B[N-N//2:N])
answer = ['?']*N
left = 0
right = N-1

for idx in range(N):
    if idx%2:
        if A and A[0] >= B[-1]:
            answer[right] = B.popleft()
            right -= 1
        else:
            answer[left] = B.pop()
            left += 1
    else:
        if B and B[-1] <= A[0]:
            answer[right] = A.pop()
            right -= 1
        else:
            answer[left] = A.popleft()
            left += 1


print(''.join(answer))

 

문제를 보면, 구사과는 가장 사전순으로 빠르게,

 

큐브러버는 사전순으로 느리게이다.

 

이때 그냥 생각해보면 정렬하고, 

 

앞에서부터, 구사과는 작은걸

 

큐브러버는 큰걸 둔다고 생각을 하고 두면, 안된다.

 

이 문제는 최적의 방법이므로, 두사람의 패를 알고 있다고 가정을 하고 풀어야한다.

 

만약 구사과가 가진 문자열 중 가장 작은 것이, 큐브러버의 문자열중 가장 큰것보다, 작을때에는

 

작은걸 제일 앞에 두면 된다.

 

하지만 가장 작은것이 큐브러버 문자열 중 가장 큰것보다 크거나 같을때에는,

 

자신이 무조건 써야하는 패중에서 가장 큰걸 가장 뒤에 두는게 사전순으로 빠르게 하는방법이다.

 

이와 같이

 

큐브러버도 자신이 가진 문자열 중 가장 큰 것이, 구사과가 가진 가장 작은 문자열보다 클때에는 

 

앞에 자신의 가장 큰 문자열을 위치시키면 된다.

 

하지만 구사과가 가진 작은 문자열보다 자신이 가진 가장 큰 문자열이 작을때에는

 

자신이 가진 가장 작은 문자열을 뒤로 보내는것이, 사전순으로 늦게 하는방법일것이다.

 

이런식으로 해서 문제를 풀면된다.

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

[BOJ/백준] 2695 공  (0) 2022.06.21
[BOJ/백준] 3343 장미  (1) 2022.05.11
[BOJ/백준] 19566 수열의 구간 평균  (0) 2022.01.15
[BOJ/백준] 12912 트리 수정  (0) 2021.12.23
[BOJ/백준] 2240 자두나무  (0) 2021.12.04

GET all list

GET detail : retrieve

POST create 

PUT update

DELETE delete

PATCH partial_update

운영체제란 무엇인가?

  • 운영체제란 ?
    • 컴퓨터 하드웨어 바로 위에 설치되어 사용자 및 다른 모드 소프트웨어와 하드웨어를 연결하는 소프트웨어 계층
    • 협의의 운영체제
      • 운영체제의 핵심 부분으로 메모리에 상주하는 부분
    • 광의의 운영체제
      • 커널 뿐 아니라 각종 주변 시스템 유틸리티를 포함한 개념

운영체제의 목적

  • 컴퓨터 시스템의 자원을 효율적으로 관리
    • 프로세서 기억장치 입출력 장치 등의 효율적 관리
      • 사용자 간의 형평성 있는 자원 분배
      • 주어진 자원으로 최대한의 성능을 내도록
    • 사용자 및 운영체제 자신의 보호
    • 프로세스, 파일, 메시지 등을 관리
    • 효율성이 높게 관리, 하지만 효율성만 최고로 할시, 형평성이 맞지 않게 된다.
  • 컴퓨터 시스템을 편리하게 사용할 수 있는 환경을 제공
    • 운영체제는 동시사용자/ 프로그램들이 각각 독자적 컴퓨터에서 수행되는 것 같은 환상을 제공
    • 하드웨어를 직접 다루는 복잡한 부분을 운영체제가 대행

운영체제의 분류

  • 단일 작업(single tasking)
    • 한 번에 하나의 작업만 처리
  • 다중 작업(multi tasking)
    • 동시에 두개 이상의 작업처리
  • 최근에는 대부분의 운영체제는 다중작업이 가능한 운영체제
  • 단일 사용자(single user)
    • MS-DOS,MS Windows
  • 다중 사용자(multi user)
    • UNIX, NT server
  • 일괄 처리(batch processing)
    • 작업 요청의 일정량 모아서 한꺼번에 처리
    • 작업이 완전 종료될 때까지 기다려야함
  • 시분할(time sharing)
    • 여러 작업을 수행할때, 컴퓨터 처리능력을 일정한 시간단위로 분할하여 사용
    • 일괄처리 시스템에 비해 짧은 응답시간을 가짐
    • interactive한 방식
  • 실시간(Realtime)
    • 정해진 시간 안에 어떠한 일이 반드시 종료됨이 보장되어야하는 실시간 시스템을 위한 OS
      • 원자로/공장 제어, 미사일 제어, 반도체 장비, 로보트 제어
    • 실시간 시스템 개념 확장
      • Hard realitime system
      • Soft realtime system

용어 정리

  • multitasking : 다수의 작업이 돌아가면서 진행되는 방식
  • multiprogramming : 메모리에 여러 프로그램이 올라가는 방식
  • time sharing : cpu의 시간을 분할하여 나누어 쓴다는 의미
  • multiprocess
  • Multiprocessor : 하나의 컴퓨터에 CPU가 여러개 붙어있는 컴퓨터

운영체제의 종류

  • 유닉스(UNIX)
    • 코드의 대부분을 C언어로 작성
    • 높은 이식성
    • 최소한의 커널 구조
    • 복잡한 시스템에 맞게 확장 용이
    • 소스코드 공개
    • 프로그램 개발에 용이
  • DOS(Disk Operation System)
    • MS사에서 1981년 IBM-PC를 위해 개발
    • 단일 사용자용 운영체제, 메모리 관리능력의 한계
  • MS Windows
    • MS사의 다중 작업용 GUI 기반 운영체제
    • Plug and Play, 네트워크 환경 강화
    • DOS용 응용 프로그램과 호환성 제공
    • 풍부한 자원 소프트웨어

운영체제의 구조

  • CPU-memory - DISK - I/O device
  • CPU 스케줄링 : CPU를 어떻게 관리를 해줄까.?
  • 메모리 관리 : 한정된 메모리를 관리하는 방법
  • 파일 관리 : 디스크에 파일을 어떻게 보관하지
  • 입출력 관리 : 각기 다른 입출력 장치와 컴퓨터간에 어떻게 정보를 주고받게 하지.?
def solution(board, skill):
    answer = 0
    N = len(board)
    M = len(board[0])
    skill_board = [[0 for i in range(M+2)] for _ in range(N+2)]
    cnt = 0
    for sk in skill:
        sk_type, r1,c1,r2,c2 ,degree = sk
        if sk_type == 1:
            degree = -degree
        r1 +=1; r2+=1; c1+=1; c2+=1
        skill_board[r1][c1] += degree
        skill_board[r1][c2+1] -= degree
        skill_board[r2+1][c1] -= degree
        skill_board[r2+1][c2+1] += degree
    for x in range(1,N+1):
        for y in range(1,M+1):
            skill_board[x][y] = skill_board[x][y] + skill_board[x-1][y] + skill_board[x][y-1] - skill_board[x-1][y-1]
    for x in range(N):
        for y in range(M):
            if board[x][y] +skill_board[x+1][y+1] >0:
                answer += 1
    return answer

이 문제도 실전에서 풀지 못했던 문제였다.

 

7번 문제에 너무 힘을 쏟은 나머지, 마지막 20분동안 풀다가 범위 측정을 제대로 못해서, 풀지 못한 문제였다.

 

평소 2차원 누적합을 잘 다루지 않다보니, 범위를 구하는데 실수를 했고, 그 범위의 누적합을 구하는데 연산을 실후 했다.

 

이 문제에서 중요한 것은 폭발 범위에 맞춰서 누적합을 할 수 있게, 숫자들을 정리해 놓고, 누적합을 구하면 되는 문제이다.

 

폭발이 시작하는 r1,c1에는 +degree을 해주고,

 

폭발이 끝나는 위치인 r2+1,c1 , r1,c2+1에는 -degree을 해준다.

 

그리고 중요한 것은 r2+1, c2+1 에서는 +degree를 해주는 것이다.

 

이 누적합을 마킹해놓은 상태에서 가로로 1번 누적합 세로로 1번 누적합을 진행을 한다고 생각을 해보면, 왜 그 위치에서 마킹을 해줘야하는지 이해할 수 있다.

 

이 문제는 누적합이라는 접근까지 했지만, 디버깅 할 시간이 부족해 풀지 못했던 아쉬웠던 문제였다..

 

2차원 누적합은 매번 풀때마다, 햇갈려하는 유형이기 때문에 좀 더 연습해야겠다.

dx = [-1,0,1,0]
dy = [0,1,0,-1]
N,M =0,0
def B_turn(curboard,A,B,turn):
    x,y = B 
    if curboard[x][y] == 0:
        return (-1,turn)
    flag = False
    winner = []
    loser = []
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        if 0<=nx<N and 0<=ny<M:
            if curboard[nx][ny] == 1:
                new_board = [row[:] for row in curboard]
                new_board[x][y] = 0
                iswin,new_turn = A_turn(new_board,A,(nx,ny),turn+1)
                if iswin == -1:
                    winner.append(new_turn)
                else:
                    loser.append(new_turn)
                flag = True
    if flag:
        if winner:
            return (1,min(winner))
        else:
            return (-1,max(loser))
    else:
        return (-1,turn)
def A_turn(curboard,A,B,turn):
    x,y = A 
    if curboard[x][y] == 0:
        return (-1,turn)
    flag = False
    winner = []
    loser = []
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        if 0<=nx<N and 0<=ny<M:
            if curboard[nx][ny] == 1:
                new_board = [row[:] for row in curboard]
                new_board[x][y] = 0
                iswin,new_turn = B_turn(new_board,(nx,ny),B,turn+1)
                if iswin == -1:
                    winner.append(new_turn)
                else:
                    loser.append(new_turn)
                flag = True
    if flag:
        if winner:
            return (1,min(winner))
        else:
            return (-1,max(loser))
    else:
        return (-1,turn)

def solution(board, aloc, bloc):
    global N,M
    N = len(board)
    M = len(board[0])


    return A_turn(board,aloc,bloc,0)[1]

 

 작년 카카오 마지막 문제로, 풀지 못했던 문제였다.

 

비슷하게 접근을 했지만, 원하는 정답을 구하지 못했고,

 

문제가 나오자마자 풀었다.

 

비슷한 느낌의 문제는 https://www.acmicpc.net/problem/16571

 

16571번: 알파 틱택토

현재까지 진행된 틱택토 게임 보드가 띄어쓰기로 구분되어 3줄에 걸쳐 주어진다. 0은 빈칸, 1은 X, 2는 O를 의미한다. 단, 항상 X가 선공이다. 그리고 이미 게임이 종료된 상태는 입력으로 주어지

www.acmicpc.net

위의 문제이고,

 

이 문제에서도, 완전탐색을 통해, 자신이 지는지, 이기는지를 판별을 하고,

 

자신이 이길 가능성이 있으면, 이길때의 최소 턴을 return 해주고,

 

전부 질때에는 최대 turn을 반환을 해주면 되는 것이다.

 

이 문제에서 지는 조건은 총 2가지로,

 

4방향으로 움직이고자할때, 움직이지 못하면, 지는 것이고,

 

두번째는 움직이고자할때, 내가 밟고 있는 발판이 사라진 상태이면 지는 것이다.

 

이 문제를 풀때,

 

예를 들어 현재 사용자(A)가 진다고 생각했을때 나는 -1과 turn을 반환을 해주었다.

 

그러면 상대방(B) 입장에서는 이 값을 return 되었을때 -1이 오게 되면, 자신이 이기게 되는 것이다.

 

그러므로, winner라는 리스트에 턴 값을 저장을 해주었다.

 

결국에는 두 사용자는 하나는 패배하게 될것이고, 한 사용자는 이기게 될것이다.

 

그래서 이기게 된 사용자는 1을 반환을 하게 만들었고,

 

이 값을 받은 입장에서는 자신의 패배가 되는 것이다.

 

그러면 X라는 턴에서 한 사용자가 모든 경우를 다 탐색하게 되면, 1 또는 -1을 받게 되어, 자신이 이기게 될지, 지게 될지를 알게 될것이다.

 

문제에서 우리는 두 사용자는 이기게 되도록 수를 둔다고 했으니, 받는 값 중에서 이기게 되는 경우가 단 1번이라도 있게 되면,

1 과 이길수 있는 경우 중에 최소 턴을 반환한다.

 

그러나 모든 경우에도 자신이 지게 되는게 확정적이라 생각되면, 최대 turn을 반환해주면 된다.

 

그래서 -1과 지는 경우 중에서 최대 턴을 반환해주도록 하도록 함수를 짜주면 된다.

 

이렇게 함수를 짜놓고, 재귀를 돌리게 되면, 문제를 해결 할 수 있는 문제였다.

 

실전에서 문제를 푸는데 틀린 이유 중 하나는, 현재 위치에서 지는 경우에 대해서 탐색을 하고, return을 해줘야하는데, 

 

최선의 수를 두지 않는, 미래의 수를 계산을 해서 return을 해줘서 틀렸던 문제였다.

 

실전에서 이 문제에 시간을 오래 소비해서 결국 6번도 풀지 못한거 보면, 문제를 해결할 때, 시간 분배를 잘해야겠다.

import sys
from collections import defaultdict
def input():
    return sys.stdin.readline().rstrip()

N,M = map(int,input().split())

arr = list(map(int,input().split()))


prefix_sum = [0] + arr[:]
result = 0
num_dict = defaultdict(int)
for i in range(1,N+1):
    prefix_sum[i] += prefix_sum[i-1]
    calc = prefix_sum[i] - M*i

    result += num_dict[calc]
    num_dict[calc] += 1


print(result+num_dict[0])

몇달 전에 푼 문제라 정확히 복기는 못하지만, 현재 생각 나는대로 복기를 할려고 한다.

 

 이 문제는 누적합을 이용해 구간의 평균합의 개수를 구하는 것이다.

 

 

현재까지의 누적합에서 지금까지의 평균의 총합을 빼주게 된다면, 

 

현재 위치에서 평균이 되기 위해 사라져야할 값이 보인다.

 

이 점을 이용해 푸는 문제이다.

 

구해야하는 평균이 K일때

 

즉 현재의 누적합 - 구간*K 을 했을때 나오는 값을 calc이라 했을 때,

 

이 calc 만큼만 사라지면 현재 구간 앞에서 얻을 수 있는 평균이 K인 구간의 개수가 되는 것이다.

 

이 문제는 누적합에서 구간의 평균합을 뺀 숫자와 일치하는 개수를 계속 누적해서 더해주면 풀 수 있는 문제이다.

 

그리고 마지막에 0을 더해준 이유는 현재 구간의 앞에서 나올 수 있는것을 더해준 것이니,

전체 구간에서 더해줄 필요가 있어서, 마지막에 더해주는 것이다.

 

6달전에 풀었던 것을 다시 복기할려니 정확하게 설명은 못했지만, 위와 같은 방법을 활용하면 된다.

 

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

[BOJ/백준] 3343 장미  (1) 2022.05.11
[BOJ/백준] 16890 창업  (0) 2022.05.11
[BOJ/백준] 12912 트리 수정  (0) 2021.12.23
[BOJ/백준] 2240 자두나무  (0) 2021.12.04
[BOJ/백준] 23291 어항정리  (0) 2021.11.07

09. Hook Flow

Hook이 동작하는 순서에 대해서 설명한다.

현재까지 배운 useEffect와 useState의 동작하는 순서에 대해서 말하겠다.

App render -> useState : initial -> rendering End -> useEffect : 등록한 순서대로

작동을 한다. 여기서 상기해야할 점은 useEffect는 사이드 이펙트를 관리하는 Hook이기 때문에 전부 그려지고 난뒤에, 작동을 하는 것을 알 수 있다.

flow chart

<body>
  <div id="root"></div>
  <script src="https://unpkg.com/react@16.12.0/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone@7.8.3/babel.js"></script>
  <script type="text/babel">
    // https://github.com/donavon/hook-flow

    function Child() {
      console.log('%c    Child: render start', 'color: MediumSpringGreen')

      const [count, setCount] = React.useState(() => {
        console.log('%c    Child: useState callback', 'color: tomato')
        return 0
      })

      React.useEffect(() => {
        console.log('%c    Child: useEffect no deps', 'color: LightCoral')
        return () => {
          console.log(
            '%c    Child: useEffect no deps cleanup',
            'color: LightCoral',
          )
        }
      })

      React.useEffect(() => {
        console.log(
          '%c    Child: useEffect empty deps',
          'color: MediumTurquoise',
        )
        return () => {
          console.log(
            '%c    Child: useEffect empty deps cleanup',
            'color: MediumTurquoise',
          )
        }
      }, [])

      React.useEffect(() => {
        console.log('%c    Child: useEffect with dep', 'color: HotPink')
        return () => {
          console.log(
            '%c    Child: useEffect with dep cleanup',
            'color: HotPink',
          )
        }
      }, [count])

      const element = (
        <button onClick={() => setCount(previousCount => previousCount + 1)}>
          {count}
        </button>
      )

      console.log('%c    Child: render end', 'color: MediumSpringGreen')

      return element
    }

    function App() {
      console.log('%cApp: render start', 'color: MediumSpringGreen')

      const [showChild, setShowChild] = React.useState(() => {
        console.log('%cApp: useState callback', 'color: tomato')
        return false
      })

      React.useEffect(() => {
        console.log('%cApp: useEffect no deps', 'color: LightCoral')
        return () => {
          console.log('%cApp: useEffect no deps cleanup', 'color: LightCoral')
        }
      })

      React.useEffect(() => {
        console.log('%cApp: useEffect empty deps', 'color: MediumTurquoise')
        return () => {
          console.log(
            '%cApp: useEffect empty deps cleanup',
            'color: MediumTurquoise',
          )
        }
      }, [])

      React.useEffect(() => {
        console.log('%cApp: useEffect with dep', 'color: HotPink')
        return () => {
          console.log('%cApp: useEffect with dep cleanup', 'color: HotPink')
        }
      }, [showChild])

      const element = (
        <>
          <label>
            <input
              type="checkbox"
              checked={showChild}
              onChange={e => setShowChild(e.target.checked)}
            />{' '}
            show child
          </label>
          <div
            style={{
              padding: 10,
              margin: 10,
              height: 30,
              width: 30,
              border: 'solid',
            }}
          >
            {showChild ? <Child /> : null}
          </div>
        </>
      )

      console.log('%cApp: render end', 'color: MediumSpringGreen')

      return element
    }

    ReactDOM.render(<App />, document.getElementById('root'))
  </script>
</body>
  • 위의 코드를 실행해보면 Hook Flow에 대해서 알 수 있는데, 렌더링시

    Parents render -> Parents useState Call -> Parents render end -> Child render -> child useState Call -> Child render end -> (Child useEffect clean up) -> Child useEffect -> (Parents useEffect clean up) -> Parents useEffect

    cleanup은 최초 렌더시 되지 않지만, 만약 변경사항이 존재할때에는 cleanup들이 먼저 발생을 하고 useEffect가 작동한다.

  • 또한, vue와 비슷하게 moutend 까지는 Parents Component가 먼저하지만, 그 이후로는 Child Component가 모든 과정이 끝나야 Parents의 UseEffect를 하는 것을 알 수 있다.

  • 이 부분에 대해서 다른 Hook을 공부하고 더 업데이트를 해야겠다.

08. Custom Hook

반복되는 Hook 들을 커스텀 된 훅으로 묶어서 사용하는 방식

  • 반복되는 로직을 재사용이 쉽도록 만들어서 사용하며, 커스텀 Hook을 만들 때에는 use라는 단어를 앞에 두어서 만들어준다.
import { useState, useCallback } from 'react';

function useInputs(initialForm) {
  const [form, setForm] = useState(initialForm);
  // change
  const onChange = useCallback(e => {
    const { name, value } = e.target;
    setForm(form => ({ ...form, [name]: value }));
  }, []);
  const reset = useCallback(() => setForm(initialForm), [initialForm]);
  return [form, onChange, reset];
}

export default useInputs;

< 출처 : 21. 커스텀 Hooks 만들기 · GitBook>

위와 같이 일련의 과정들을 하나의 Hook 함수로 만들어서 사용하면 된다.

이 커스텀 Hook은 많이 만들어보고 공통적인 과정을 하나의 함수로 바꾸는 연습을 해봐야할 것 같다.

+ Recent posts