아래 처럼 모든 unvisited node를 돌면서 topologicalSort를 불러주는 방법이 있는가 하면, 각 노드로 들어가는 edge를 수를 트래킹하면서(indegree map) 트래버스할 수 도 있다.
using incoming edge
1 2
1 -> 2 3 -> 2 -> 5
위와 같은 그래프가 있다고 치자.. 그럼 각노드의 incoming edge수를 세어보면 이렇게 된다. 1: 0 3: 0 2: 2 5: 1
incoming edge가 0라는 말은 아무 prerequisite이 없으니 이 노드부터 traverse할 수 있다는 얘기니까 1/3번 노드를 가장먼저 진행하고 1/3번을 제거하면 2의 incoming edge는 0가 된다. 그러니 2를 진행할 수 있고 2가 없어지면 5의 incoming edge가 0가 되어서 5도 없앨 수 있다. 이렇게 topological sort가 되는 것이다.
using dfs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
booleantopologicalSort(int[][] map,int[] visited, int here, List<Integer> path ){ if(visited[here] == 2) returnt true; // if visited return if (visited[here] == 1) returnfalse; // detect cycle
visited[here] = 1; // open
for (int i = 0; i < map[here].length; i++){ if(map[here][i]==1) topologicalSort(map, visited, i, path); }
visited[here] = 2; // close path.add(here); returntrue; }
detect cycle
cycle의 경우, directed graph는 visited의 state(1:open, 2:close)까지 봐야 하는 반면, undirectional graph의 경우는 visited의 여부만 보면 된다. 즉 visited에 node에 들어가면 바로 cycle이라고 판정하면 된다.
Given array [A0,A1, - ,An ], sliding window of size k which is moving from the very left of the array to the very right. find max/min of each sliding window.
naive
O(NK) 로 가능.
using priority_queue
슬라이딩 윈도우의 값들을 TreeSet으로 오더를 유지해주면 O(Nlog(K)) 정도로 풀 수 있다. O(logK)는 추가 및 삭제에 걸리는 시간
linear
O(N)도 가능!
intuition:
윈도우 안의 값이 추가될때, 기존 최대보다 크다면 기존 것은 버리고 새로운 값이 최대가 된다. 그러므로 자연스럽게 내림차순 정렬이 된다!
값이 삭제될때, 최대값이 삭제되면 그 다음 값이 최대값이 된다.
구현 :
window안의 값을 deque로 관리하는데 head에는 최소 값, tail에는 최대값이 들어가게 관리.
whenever add a[i], while(a[i]>head) 이면 head 삭제. 윈도우의 값보다 작은 값들은 모두 버린다. 왜 그럴까? (버려지는 값들은 a[i]가 있는한 최대값이 될 수 없으므로).
그럼 sliding window가 범위를 벗어날때, 삭제는 어떻게 하면 될까? deque를 돌면서 지우면 될까? 그렇게 하면 O(N)을 만족할 수 없고, 우리는 tail값만 사용할 것이므로 tail이 현재 window에 있는지만 보면 된다. 따라서, 각 스텝마다 윈도우를 벗어나면 지우면 된다.
publicint[] maxSlidingWindow(int[] nums, int k) { int N = nums.length; int R = N-k+1; if(R<=0) returnnewint[]{}; int[] ret = newint[R]; LinkedList<Integer> deque = new LinkedList<>(); //first:min, last:max
for (int i = 0; i < N; i++) { int start = i-k+1; int end = i;
Given an array of integers A and an integer k, find a subarray that contains the largest sum, subject to a constraint that the sum is less than k?
intuition
안타깝게도 위의 제약조건이 들어가면 dp방식으로는 풀수 없다. 그리고 값을 비교해야 하기 때문에 sort가 필요하다. 그러면 O(longN)의 complexity가 붙겠지.
range sum은 보통 array의 처음부터 cumulative sum을 해서 cum[j]-cum[i] where i<j 을 해주면 구할 수 있다.
여기서 더 발전시키면, 왼쪽에서 부터 cum[j]를 TreeSet에 추가하기 전에, 트리에 이미있는 값들은 소트가 되어 있으므로 트리에 있는 값중 최적의 갑을 찾아낼 수 있다. 아래에서 cum[j],k는 상수 이므로 TreeSet의 값중에서 ceiling 를 찾으면 된다.
cum[j]-cum[i]<=k, where i cum[i]>=cum[j]-k
implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14
intmaxSumLessThanK(int[] a, int k){ int ret=Integer.MIN_VALUE; int sum=0; TreeSet<Integer> set = new TreeSet<>(); set.add(0); for (int i = 0; i < N; i++){ sum+=nums[i]; int min = set.ceiling(sum-k); ret=Math.max(ret, min); set.add(sum); }
최근에 docker를 사용해볼 기회가 있어서 몇가지 컨셉 도움이 되는 것들을 정리해 보기로 한다. docker이전엔 virtual machine(VM)이 있었고 이것으로 많이 사용했지만 VM의 문제는 무겁다는 것. 그래서 light하게 에뮬레이션 할 수 있게 docker가 나오기 시작함. 개발환경/서버환경 설정등으로 사용하면 좋은 use case가 됨.
image vs container
처음 헷갈린 것은 image와 container의 관계. image는 read-only이고 container는 image를 기반으로 실행되고 있는 것을 의미함. class와 instance의 관계라고 하면 적당한 비유가 될 것 같다.
name
image
conatiner
list
docker images
docker ps
build
docker image 를 빌드하려면 Dockerfile을 작성하면 되는데, 이 파일은 일련의 명령들을 순차적으로 실행해서 내가 원하는 이미지를 만드는 형식이다.
1 2 3
# build using current directory's Dockerfile docker build . docker build -t myimage:latest . # set tag as myimage:latest
run
docker run
-p host_port:container_port : port forwarding
-v host_volume:container_volumen : volume mapping
-it : open tty interactive shell
–net=host : host network을 그대로 사용하게 함. 즉, expose된 모든 port들은 외부에서 접근가능하게 됨. default는 port forwarding을 해줘야만 접근이 가능함.
-e : env va를 다커로 넘겨주는 명령. 환경변수가 많을 경우 --env-file env.list 옵션을 사용할 수 있음.
1 2 3 4
# run nginx docker image with 8000 port docker run -it -p 8000:80 nginx docker run -d -e POSTGRES_ENV_POSTGRES_PASSWORD='foo' nginx docker run --env-file ./env.list ubuntu bash
exec
docker exec -it nginx bash
run과 기본적으로 같지만, 이미 실행되어 있는 container에서 실행하는 명령이다. 즉, 이미 실행되어 있는 웹서버의 bash shell로 들어가서 뭔가 확인해야 할것이 있다면 아래처럼 명령을 실행하면 된다.
delete images
간혹 여러개 이미지를 지워야 할 일이 있는데 아래 커멘드로 한방에 훅. 그러나 다른 것 지우지 않게 조심해야 함.
만들어진 docker image를 docker hub에 push하면 나중에 재사용할 수 있기 때문에 빌드 시간을 줄 일 수 있다. 그 전에 중요한 것은 image의 이름이 <dockerhub_id>/<image_name>의 형식으로 되어 있어야 한다.
1 2 3 4 5 6 7 8 9
$ docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE docker-whale latest 7d9495d03763 38 minutes ago 273.7 MB # change docker tag docker tag 7d9495d03763 nberserk/docker-whale:latest #login to docker hub docker login --username=yourhubusername --email=youremail@company.com # push image docker push nberserk/docker-whale
Dockerfile
add
1 2 3
# local 의 dev directory를 container의 /code/dev 로 recursive copy를 하고 싶다면 아래처럼. # 만약 `add dev /code` 로 주면 dev dir의 파일을 /code로 카피한다. 왜 이렇게 헷갈리게 동작을 정의 했을까.. add dev /code/dev
copy
1 2
COPY dist/. /usr/share/nginx/html/ # copy files under dist folder COPY dist /usr/share/nginx/html/ # copy dist directory to html folder
위의 예 처럼 폴더안에 든 파일만 카피를 하고 싶다면 <folder>/. 이런식으로 기술해 주면 된다.
CMD vs ENTRYPOINT
ENTRYPOINT는 디폴트로 실행하는 포인트이고 디폴트는 sh -c 이다. CMD는 이 ENTRYPOINT의 parameter가 된다. 자세한 것은 여기를 참고.
ENTRYPOINT를 내가 만든 shell로 대체해서 커스텀화 할 수 있다. docker-entrypoint.sh로 돌리고 CMD로 디폴트로 실행될 파람을 받고 등등..
FROM python:2.7 ENV PYTHONUNBUFFERED 1 RUN mkdir /code WORKDIR /code ADD requirements.txt /code/ RUN pip install -r requirements.txt ADD . /code/
requirements.txt는 아래처럼 작성한다.
1 2 3
Django psycopg2 MySQL-python
이렇게 하면 python:2.7 docker image에 pip로 requirements.txt에 있는 패키지를 설치해서 django ready상태가 되고 호스트의 WORKDIR을 /code로 마운트해서 장고 앱을 실행할 수 있는 상태로 만든다. 그 후 아래 명령을 실행하면 장고가 프로젝트 템플릿을 만들어 준다. MyApp 하위에
docker-compose run web django-admin.py startproject MyApp .
그후 mysql을 연결하는 작업을 해야 하는데 MyApp/settings.py 파일의 DATABASES 부분을 아래처럼 수정.
val config = new Configuration() //config.set("fs.s3.impl", "org.apache.hadoop.fs.s3.S3FileSystem") val fs = FileSystem.get( URI.create(srcPath), config) FileUtil.copyMerge(fs, new Path(srcPath), fs, new Path(dstPath), false, config, null) }
revision history
2016/1/11 initial draft
About
Etiam porta sem malesuada magna mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.