https://github.com/brave-people/brave-tech-interview 를 참고하였습니다. 

 

한컴오피스 '한글'을 클릭 후 빈 화면에 커서가 깜빡이고 있다. 이때 hello world를 작성하면 컴퓨터 내부에서 어떤일이 발생하는가?

Process와 Thread 차이점을 설명하세요.

Process와 Program 차이점을 설명하세요.

인터럽트에 대해서 설명하세요

DMA 존재 이유에 대해서 설명하세요.

운영체제는 다중 유저가 하나의 컴퓨터의 자원을 사용할 때 자원의 '보호'를 합니다. 어떠한 보호를 하는지 설명하고 시나리오를 설명하세요

synchronized에 대해 아는 바를 전부 이야기하세요.

함수호출과 시스템 콜의 차이에 대해서 설명하세요.

인터럽트와 시스템 콜의 차이에 대해서 설명하세요.

스레드와 멀티스레드에 대해서 설명하세요.

Deadlock의 발생 조건과 Deadlock을 깨기 위해서 어떻게 해야하나요?

Virtual Memory에 대해서 설명하시고 사용했을 때 장점에 대해서 설명하세요.

Page Fault를 줄이는 방법에 대해서 설명하세요

OS에서 프로세스는 CPU와 메모리 사이에 MMU(Memory Management Unit)를 두어서 다른 프로세스에 접근할하지 못합니다. 그러나 GDB와 같은 디버거의 경우 다른 프로세스에 접근하여 절대적 메모리 주소와 값을 읽어올 수 있습니다. 어떻게 가능한지 동작 방식에 대해서 설명하세요.

이중모드의 특징과 장점에 대해 설명하세요

임계구역 문제가 무엇이고 어떻게 해결하는지 설명하시오

System Call에 대해서 설명하세요

64비트와 32비트 차이는 무엇인가요?

마우스로 한글 바로가기를 클릭했을 때 컴퓨터에서 일어나는 모든 일에 대해서 설명하세요.

도현이의 집 N개가 수직선 위에 있다. 각각의 집의 좌표는 x1, ..., xN이고, 집 여러개가 같은 좌표를 가지는 일은 없다.

도현이는 언제 어디서나 와이파이를 즐기기 위해서 집에 공유기 C개를 설치하려고 한다. 최대한 많은 곳에서 와이파이를 사용하려고 하기 때문에, 한 집에는 공유기를 하나만 설치할 수 있고, 가장 인접한 두 공유기 사이의 거리를 가능한 크게 하여 설치하려고 한다.

C개의 공유기를 N개의 집에 적당히 설치해서, 가장 인접한 두 공유기 사이의 거리를 최대로 하는 프로그램을 작성하시오.

입력

첫째 줄에 집의 개수 N (2 ≤ N ≤ 200,000)과 공유기의 개수 C (2 ≤ C ≤ N)이 하나 이상의 빈 칸을 사이에 두고 주어진다. 둘째 줄부터 N개의 줄에는 집의 좌표를 나타내는 xi (0 ≤ xi ≤ 1,000,000,000)가 한 줄에 하나씩 주어진다.

출력

첫째 줄에 가장 인접한 두 공유기 사이의 최대 거리를 출력한다.

 

예제 입력 1

5 3
1
2
8
4
9

예제 출력 1

3

 


1차 접근 (2022.1.18 못품)

가능한 집의 좌표가 10억이기 때문에 탐색 범위가 매우 크다. 따라서 이진탐색으로 접근해야한다는 점까지는 캐치를 했는데, 이진 탐색은 특정 값을 찾는 알고리즘인데 공유기 설치를 하는 범위에 어떻게 적용이 되어야 하는지 감이 잘 안 왔다. 얼마 전에 풀었던 떡볶이 떡 자르기 문제와 유사하다는 것까지는 눈치를 챘는데, 그 뒤로 2시간동안 헤매다가 결국 해설을 참고해서 이해를 한다.

 

해설 1

이진 탐색으로 가장 인접한 두 공유기 사이의 거리를 조절해가며, 매번 실제로 공유기를 설치하여 C보다 많은 개수로 공유기를 설치할 수 있는지 체크하여 문제를 해결한다. 다만 가장 인접한 두 공유기 사이의 거리의 최댓값을 찾아야 하므로, C보다 많은 개수로 공유기를 설치할 수 있다면 가장 인접한 두 공유기 사이의 거리의 값을 증가시켜서 더 큰 값에 대해서도 성립하는지 체크하기 위해 다시 탐색을 수행한다. 

 

따라서 매번 가장 인접한 두 공유기 사이의 거리 (gap)의 최소값, 최대값을 계산해주면 될 것이다. 

 

{1,2,4,8,9} 인 수열에 설치해야 하는 공유기의 수 C = 3이라고 해보자.

현재 gap은 1~8 사이의 값이다.  gap = [1,8] 사이

 

1) gap의 값을 중간에 해당하는 4로 설정하면, 공유기를 2개밖에 설치할 수 없다. 따라서 범위를 더 줄일 필요가 있다. 따라서 범위를 [1,3]으로 수정한다. 

2) 범위가 1~3이므로 gap의 값을 중간에 해당하는 2로 설정한다. 이 경우 공유기를 3개 설치할 수 있다. 다만 더 큰 값에 에 대해서도 확인해볼 필요가 있으므로 현재의 gap 값을 저장하고 gap의 값을 증가시켜서 gap이 더 커졌을 때도 가능한지 확인할 필요가 있다. 따라서 범위가 [1,3]인 상태에서 범위를 [3,3]으로 수정한다. 

3) 범위가 3~3이므로 gap의 값을 중간에 해당하는 3으로 설정한다. 이 경우 공유기를 3개 설치할 수 있다. gap이 더 커졌을 떄도 확인해봐야 하나, 현재 gap 범위는 더이상 변경이 불가능하다. 따라서 gap=3이 최적의 경우이다.

--> 솔직히 이코테 책에 있는 풀이 잘 모르겠다. 다른 블로그를 참고했다...

 

해설2

공유기 설치 길이를 움직여(이분 탐색을 통해) 적절한 집에 설치 가능한지 살펴보는 문제.

 

거리가 주어지면 공유기(router)를 몇 개 설치할 수 있는지 계산하는 router_setting 함수

첫번째 집을 start로, 첫집과 끝집의 차이을 end로 둔다

 1) 중간값mid로 충분한 설치 장소를 찾지 못했다면 거리를 줄여주고

 2) 설치된 집이 더 많다면 거리를 늘려준다.

 

Python

# 2022-01-18
# 이코테 ch15 이진 탐색 문제 Q29 공유기 설치
# https://www.acmicpc.net/problem/2110

import sys

input = sys.stdin.readline

n, c = map(int, input().split())
house = [int(input()) for _ in range(n)]
house.sort()

# 해당 거리를 유지하며 공유기를 몇대까지 설치 가능한지
def router_setting(dist):
    count = 1
    cur_house = house[0]  # 시작점 (공유기 설치)
    for i in range(1, n):  # 집 모두를 순회
        # 이전 집에서 해당 거리보다 멀리 떨어진 집이라면
        if cur_house + dist <= house[i]:
            count += 1  # 공유기 설치
            cur_house = house[i]  # 공유기 설치된 집 갱신

    return count


start = 1
end = house[-1] - house[0]  #
answer = 0

while start <= end:
    mid = (start + end) // 2
    if router_setting(mid) >= c:
        answer = mid
        start = mid + 1
    else:
        end = mid - 1

print(answer)

 

회고

이진탐색 진짜 어렵다.... 토폴로지 풀 때랑 비슷한 갑갑함이다. 익숙해질 때까지 부딪혀보자 ㅠㅠ 해설을 한시간동안이나 찾아보고 읽어봤다

해당 문제는 백준 2805번 나무 자르기와 동일한 문제이나, 백준이 시간 제한이 1초로 더 짧다.

 

입력 가능한 값의 범위가 매우 커서 이진 탐색을 사용해서 가능한 경우를 찾아야겠다고 접근해야 한다.

다만, 여기에서 알고리즘에 매몰되는 실수를 했다.

 

내가 생각했던 방식은 떡의 길이를 입력받고 해당 리스트 안에서 이진탐색을 통해 중간값을 찾은 뒤, 잘라낸 길이의 총합을 target(m)과 비교하기였다. 이렇게 되면 입력받은 리스트 안에서 중간 값이지, 전체 길이의 평균이 아니다.... ㅠㅠ 사실 이 부분도 추가로 파고들면 어찌저찌 풀 수 있을 것 같기는 하다. 

 


잘못 접근한 방식 1. 재귀함수로 이분 탐색을 구현하고, 만약 엇갈린 경우 시작값과 끝값 사이에 가능한 경우가 있다고 생각하고 그 안에서 찾아봤다. 일단 파이썬은 시간 초과나고 pypy3는 틀렸다고 나온다. 게다가 아래 for문은 이진탐색한 의미가 없게 순차 탐색을 하고 있다.... ㅋ.T

# 잘못된 방향의 접근
import sys

input = sys.stdin.readline

n, m = map(int, input().split())
data = list(map(int, input().split()))
data.sort()


def binary_search(array, target, start, end):
    if start > end:
        # array[start] ~ array[end] 사이에서 값 찾아야 함
        if array[start] <= array[end]:
            arr = [array[start], array[end]]
        else:
            arr = [array[end], array[start]]
        return arr
    mid = (start + end) // 2
    cutted = sum((i - array[mid]) if (i - array[mid]) >= 0 else 0 for i in array)

    if cutted == target:
        return array[mid]  # int형 return인 경우 바로 값 출력
    elif cutted > target:  # 너무 많이 자른 것. 더 긴 기준으로 다시 잘라보기
        return binary_search(array, target, mid + 1, end)
    else:  # 너무 적게 자른 것. 더 짧은 기준으로 다시 잘라보기
        return binary_search(array, target, start, mid - 1)


result = binary_search(data, m, 0, n - 1)

if type(result) == int:
    answer = result
else:  # 리스트가 돌아온 경우
    answer = 0
    for i in range(result[0], result[1]):
        cutted = sum((j - i) if (j-i) >= 0 else 0 for j in data)
        answer = i
        if cutted == m:
            break
        elif cutted < m:  # 작아지면 더이상 볼 필요가 없음
            answer = i + 1
            break

print(answer)

 


제대로 푼 풀이. 재귀 함수는 과하게 복잡해지는 경우라서 반복문으로 다들 많이 풀더라. 나도 그렇게 풀었다.

이렇게만 하면 원래 풀었던 방식의 불필요한 방식(그래프 안에서만 값을 찾으려 하고, 못 찾은 경우 범위를 리턴해서 그 범위 안에서 for문을 통해 값을 찾음)이 아예 사라지고 깔끔하게 이진탐색으로 풀 수 있다.

 

Python3 기준으로 백준 2803 통과했다. 

import sys

input = sys.stdin.readline

n, m = map(int, input().split())
data = list(map(int, input().split()))

start = 0
end = max(data)

answer = 0
while start <= end:
    mid = (start + end) // 2

    cutted = sum((i - mid) if (i - mid) >= 0 else 0 for i in data)

    if cutted == m:
        answer = mid
        break
    elif cutted < m:  # 적게 잘라서 더 많이 잘라야 함 (왼쪽 부분 탐색)
        end = mid - 1
    else:  # 너무 많이 자른 것. 더 적게 잘라야 하므로 오른쪽에서 보기
        answer = mid  # 이 경우에는 답이 될 수도 있으니까 저장
        start = mid + 1

print(answer)

 

위 아래로 시간초과, 틀렸습니다의 향연이 펼쳐졌었다...

리액트 프로젝트를 시작하는 가장 쉬운 방법은 create-react-app을 사용한 방법이리라 생각된다.

 

계속하여 최선 버전으로 업데이트되도록, npx 명령어를 사용하여 생성한다.

// npx create-react-app *myapp
npx create-react-app test

*myapp 자리에 원하는 프로젝트 명을 적고 실행하면, 입력한 프로젝트 명으로 폴더가 하나 만들어져 있다.

해당 폴더를 실행하면, localhost:3000 으로 가장 기본적인 react 페이지가 뜬다.

 

여기서 이제 src폴더 내에서 App.js index.js index.css 를 제외한 파일은 다 지우고 프로젝트를 시작했다. 당장은 필요없기도 하고, 많은 리액트 강의에서도 다 지우더라!

 

index.js 파일을 열어보면 다음과 같다. (버전별로 차이는 있지만 신경X)

import ReactDOM from 'react-dom';

import './index.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

 

리액트 자체는 js의 확장판이기 때문에, 기본적으로 js 문법을 따라간다. 다만 기본 js에서는 지원하지 않는 문법이 위 파일에서 2개 보인다.

 

import './index.css' <- 보통 js 파일에서는 위와 같이 import하지 않는다. 

<App /> <- js 코드 내의 HTML 코드이다. (JSX)

 

위와 같이 React가 도입한 문법은, npm run 명령어를 통해 실행되어, 개발자가 원하는 방향대로 화면에 뿌려진다. 원래대로라면 작동하지 않을 문법이 react로 인해, 브라우저로 전달되기 전 transform 되어 원하는 모습을 보여주는 것이다. 

 

그리고 또 하나 기억해야 할 것은, index.js 파일은 가장 먼저 실행되는 파일이라는 것이다. 

 

index.js가 최종적으로 실행하는 것은 다음이다.

ReactDOM.render(<App />, document.getElementById('root'));

App이라는 것은 위에서 App.js를 import했으므로, 이전에 소개했던 component이다. 

(third-party library나 js파일을 import할 때는 뒤의 확장자를 빼고 import한다)

 

document.getElementById('root')

리액트는 기본적으로 single-page-application이다. 즉, 하나의 페이지 안에서 전부 동작한다는 것이다. 유저에게 보여지는 파일은 여러개의 html로 이루어진 것 같지만, 실질적으로 리액트는 하나의 페이지만을 갖고 있다. 라우팅과 같은 부차적인 기능을 통해 다른 html로 이동하는 듯한 착각을 심어주는 것이다. 

따라서 root id를 가진 document는 어디 있느냐하면, public폴더 내의 index.html을 보면 찾을 수 있다.

(public 폴더는 잘 접근할 일은 없지만, index.html이 이곳에 있다)

 

따라서 우리는 App이라는 이름의 component를 root div 내에서 실행하는 것이다. 

(App.js는 다른 component와 달리, index.js에서 실행되는 root component이다. 추후 여러개의 component가 등장하더라도, App.js 내에서 nested 될 것이다)

 

우선 가장 기본적인 문장을 띄우도록 App.js를 작성해보았다.

function App() {
	return (
    	<div>
        	<h2>Hello, world!<h2>
        </div>
    );
}

export default App;

js 내에서 html 코드를 return하는 형식은 처음 보면 굉장히 낯선 광경이다. 이 문법은 react에 도입된 문법으로, JSX라 불린다. 이는 react가 npm start로 실행되면서 브라우저에 전달될 때는 transform하여 전될되는데, 구체적으로 어떻게 변하는지 보고싶다면 해당 리액트 프로젝트를 시작한 후 개발자 도구의 source 파일을 보면 된다. 위에서 적은 js와는 사뭇 다른 코드가 보일 것인데, 이는 리액트가 JSX를 transform하여 브라우저에 전달한 결과이다. 

 

기본적인 js와 달라 혼란스러울 수 있지만, 개발자에게 더 편한 환경을 제공해주는 것이므로 금방 익숙해지는 것이 좋다!

 


기본적인 js 문법과의 차이를 한번은 짚고 넘어가는 것이 좋을 것 같아 추가한다.

function App() {
	return(
		<div>
    		<h2>Hello world!</h2>
        	<p>my cat is rockstar</p>
    	</div>
    );
}

위의 App.js 파일에서 p 태그 하나를 추가하고 싶으면 기본 리액트 문법은 위와 같이 작성하면 된다. 하지만 기본 js 문법에 따르면 다음과 같이 작성해야한다. (imperative approach로, js에게 명료하게 하나하나 어떻게 해야할지 전달)

function App() {
	const paragraph = document.createElement('p');
    paragraph.textContent = 'my cat is rockstar';
    document.getElementById('root').append(paragraph);
	return(
		<div>
    		<h2>Hello world!</h2>
    	</div>
    );
}

 

단순히 코드만 봐도, 리액트가 좀 더 짧고 간결하다. 

'React > 개념' 카테고리의 다른 글

React Basics  (0) 2022.07.20
JS 복습하기  (0) 2022.07.20
React의 메인 개념 : component  (0) 2021.05.19

서론

React 자체를 너무 어렵게 접근할 필요는 없다. 리액트는 UI를 보다 쉽게 개발할 수 있도록 도와주는 자바스크립트 라이브러리다. 물론 Html, css, js로도 UI를 만들 수 있으나, 리액트를 사용하면 component라는 개념 덕분에 코드가 훨씬 깔끔하고 구현 난이도가 내려간다. 

 

Component란 무엇인가?

쉽게 말하자면, UI 상에서 다시 사용할 수 있는 building block이다. 단순히 표시해줘야하는 데이터만 바뀌고 UI는 그대로라면, 굳이 여러번 동일한 코드를 반복해서 작성할 필요 없이, 하나의 block을 만들고, 그 안의 데이터만 넘겨주는 방식이다.

Component 자체는 쉽게 말하자면, Html+js (+ css) 덩어리다. (css를 괄호처리한 이유는 리액트 상에서는 크게 중요한 개념이 아니라서다.) 각각의 UI 상에서 모든 걸 쪼개서 component로 구성할 수도 있다. 따라서 개발자는 UI를 구성하는 모든 요소를 쪼개서 component로 만든 뒤, 최종적으로 어떻게 UI를 그릴지 React에게 구성도를 던져주기만 하면 된다. (재사용성에 너무 집착할 필요는 없다.) 

 

Component 단위의 구성은 개발자에게 Reusability & Separation of Concerns를 제공한다.

불필요한 코드의 반복도 없고, 한 곳에서 지나치게 많은 요소를 관리할 필요도 없다. 각각의 component는 자신이 수행해야 하는 하나의 목표만 집중하면 되는 것이다. 

'React > 개념' 카테고리의 다른 글

React Basics  (0) 2022.07.20
JS 복습하기  (0) 2022.07.20
React : create-react-app  (0) 2021.05.19

로그인, 로그아웃 여부에 따라 Header 조건부 렌더링하기 (1)

- component가 모두 접근할 수 있도록 context를 사용한다. 

 

context.js에서 createContext import 해준 뒤 다음과 같이 기본적으로 context와 provider 작성을 해준다.

 

// UserContext : Application 내의 데이터 저장소
const UserContext = React.createContext();

const UserContextProvider = ({children}) => {
	<UserContext.Provider>{children}</UserContext.Provider>
}

export default UserContextProvider;

 

여기에서 추가적으로 값을 전달해야할 것이며, state도 갖고 있어야 한다. 

http://postmafia.kro.kr 사이트로 도메인도 구매하고, 임시방편으로 웹포워딩 걸어서 index.html이 뜨는 것까지 해뒀다. 이제 문제는 webRTC가 로컬 환경이 아닌 경우, SSL을 직접 설정해서 https 환경을 구축해줘야 제대로 돌아간다는 건데, 나머지는 어떻게 보고 따라가겠는데 진짜 이건 어디부터 건드려야될지 감도 안잡힌다.

'개발 프로젝트 > 온라인 마피아' 카테고리의 다른 글

WebRTC - AWS 호스팅하기 (3)  (0) 2020.10.02
WebRTC - OpenSSL 삽질 (2)  (0) 2020.10.02
WebRTC - 기초부터 차근차근 (1)  (0) 2020.10.02

WebRTC가 로컬 환경이 아니면 보안 문제로 카메라 권한을 원활하게 받아오지 못한다는 것은 알지만 우선 s3 버킷에 올려서 호스팅부터 해보기로 했다. 

 

자, 내가 필요한 건 1. 서버 2. 도메인 이렇게 두가지인데, 학회 수준 프로젝트에서 도메인을 매년 만얼마씩 주면서 구매할 필요성을 못 느껴서 무료 도메인을 서치하던 중 좋은 사이트를 발견했다.

 

내도메인.한국이라는 사이트인데, 회원가입만 하면 무료로 도메인을 발급받을 수 있다. (물론 .com같은 도메인은 아니긴 하다.)

 

우리 프로젝트 노션명을 따와서 postmafia.kro.kr를 발급받았다. 

 

자세한 설정창이 뜬다.

 

Route 53

AWS 로 이동하여, route 53에 들어간다. 아래 이미지는 이미 호스팅 영역이 추가되어 있지만, '호스팅 영역 생성' 버튼을 클릭하여 추가해준다. 

 

굳이 route53에서 도메인을 안사도 되긴 하다

 

도메인 이름의 postmafia.kro.kr을 클릭하면 4개의 네임서버를 볼 수 있는데, 내도메인한국의 설정창에서 CNAME 칸에 추가로 입력해줬다. 여기서 입력해줘야하는 네임서버가 4개라서 이따구로 적어놨는데 나중에 수정해야겠다..!

 

별칭 1234 뭐여 이게,,, ㅠㅠ

 


Amazon s3

s3 버킷을 생성하고, step5 파일을 업로드한 뒤, 정적 웹사이트 호스팅을 걸어두었다. 왜인지 모르겠지만 postmafia.kro.kr으로 접속했을 때 바로 인덱스 문서(index.html)로 넘어가지 않는다.

DNS 설정에서 별칭을 다 저렇게 정해놔서 그런건가..? 그렇다고 하기에는 1.postmafia.kro.kr로 접속해도 시간이 너무 오래 걸린다고 하고 안 뜬다.. ㅠㅠㅠ 우선은 엔드포인트로 도메인 웹포워딩을 걸어뒀다 ㅠㅠ 흐엉 속상해

 

근데 2시간 걸려서 http:// 환경 미완성 구축해놓은 상태인데 제대로 webRTC를 띄우기 위한 https:// 설정은 언제 하지..?!

 

 

(s3버킷 하다보니까 안교수님 강의실 미완성상태인게 너무 눈에 밟힌다... 올해 안에는 끝내야될텐데 아주 첩첩산중이야~)

'개발 프로젝트 > 온라인 마피아' 카테고리의 다른 글

WebRTC - https, SSL (4)  (0) 2020.10.02
WebRTC - OpenSSL 삽질 (2)  (0) 2020.10.02
WebRTC - 기초부터 차근차근 (1)  (0) 2020.10.02

+ Recent posts