❓  문제

땅따먹기

 

🛎️  아이디어

1. 2번째 행부터 돌면서 윗 줄의 최댓값을 더해준다. 단 본인 열은 제외한다.

2. 마지막행에서는 이전 행까지의 최댓값들을 더한 값이 있음. 따라서 마지막행에서의 max값을 리턴한다.

 

💻  풀이

def solution(land):
  row = len(land)
  column = len(land[0])

  for r in range(1, row):
    for c in range(column):
      land[r][c] += max(land[r - 1][:c] + land[r - 1][c + 1:])

  return max(land[row - 1])

print(solution([[1,2,3,5],[5,6,7,8],[4,3,2,1]]))

 

❓  문제

다리를 지나는 트럭

 

🛎️  아이디어

  1. bridge 길이 만큼의 deque를 생성한다.

  2. 모든 트럭이 다리에 올라갈 때까지 while문을 돈다.

  3. bridge에서 popleft를 통해 한 칸 씩 왼쪽으로 옮겨간다. (rotate와 다름. rotate는 1->2->3->1 처럼 돌기 때문)

  4. 새롭게 들어갈 트럭의 무게와 현재 bridge의 무게를 더해서 견딜 수 있는지 확인한다.
    • 견딜 수 있다면 새롭게 들어갈 트럭의 무게를 더하고
    • 견딜 수 없다면 0을 더한다.

 

💻  풀이

# 최대 bridge_length대 올라갈 수 있음. (다리의 길이)
# weight만큼 버틸 수 있음.
# 다리에 완전히 오르지 않았다면 무게를 무시한다.

from collections import deque

def solution(bridge_length, weight, truck_weights):
    time = 0

    # 현재 올라간 트럭의 무게 합
    weight_sum = 0

    # bridge 크기만큼의 데큐 생성
    bridge = deque([0 for i in range(bridge_length)])
    while truck_weights:
        time += 1
        weight_sum -= bridge.popleft()

        # 이번에 들어갈 트럭 무게 계산
        truck = truck_weights[0]
        if weight_sum + truck <= weight:
            weight_sum += truck
            bridge.append(truck_weights.pop(0))
        else:
            bridge.append(0)

    # 마지막 트럭이 들어간 후 완전히 나올 때 까지의 시간 더해주기 (bridge_length)
    return time + bridge_length

 

🧩  포인트

- deque를 사용해서 popleft, append로 실제 다리를 건너는 것처럼 한다.

- 처음에 현재 bridge의 무게를 구할 때 sum() 함수를 사용했는데, 이럴 경우 시간 초과가 나기 때문에 sum을 담을 변수를 생성한 후 계산을 해줘야 한다.

❓  문제

행렬 테두리 회전하기

 

🛎️  아이디어

1. 회전해야하는 숫자들을 top, right, bottom, left순으로 리스트에 담는다.
    a. 단, bottom과 left는 역순으로 담는다.

2. deque의 rotate 함수를 활용해서 1칸씩 오른쪽으로 이동해준다.

3. 다시 top, right, bottom, left순으로 넣어준다.
    a. 단, bottom과 left는 역순으로 넣어준다.

 

💻  풀이

from collections import deque

def solution(rows, columns, queries):
  items = [[y + x * columns for y in range(1, columns + 1)] for x in range(rows)]
  minimum_list = []

  for x1, y1, x2, y2 in queries:
    x1 -= 1
    y1 -= 1
    x2 -= 1
    y2 -= 1

    # 위치 변경할 숫자들
    change_list = []

    # top
    change_list.extend(items[x1][y1: y2])

    # right
    for x in range(x1, x2):
      change_list.append(items[x][y2])

    # bottom
    change_list.extend(reversed(items[x2][y1 + 1: y2 + 1]))

    # left
    for x in range(x2, x1, -1):
      change_list.append(items[x][y1])

    # 최솟값 구하기
    minimum_list.append(min(change_list))

    # deque를 이용한 위치 변경
    dq = deque(change_list)
    dq.rotate(1)

    # top, right, bottom, left 순으로 넣어주기
    # top
    for y in range(y1, y2):
      items[x1][y] = dq.popleft()

    # right
    for x in range(x1, x2):
      items[x][y2] = dq.popleft()

    # bottom
    for y in range(y2, y1, -1):
      items[x2][y] = dq.popleft()

    # left
    for x in range(x2, x1, -1):
      items[x][y1] = dq.popleft()

  return minimum_list

 

❓  문제

2019 KAKAO BLIND RECRUITMENT - 후보키

 

🛎️  아이디어

1. 후보키가 될 수 있는 집합을 만든다.
    a. relation의 컬럼(column) 숫자를 가지고 만든다.
    b. 해당 결과는 (0), (1), ... (0, 1), (0, 2), ... (0, 1, 2, 3) 으로 나온다.

2. 만든 집합을 돌면서 해당 인덱스에 맞는 값들을 가지고 실제 집합을 만들어 준다.

3. 실제 집합 상태에서 중복 제거를 해준다.
      a. 유일성을 만족하는지 확인하기 위함이다.

4. 유일성을 만족한다면 (중복 제거 후에도 relation의 row길이와 같다면) 
      a. answer 배열에 해당 인덱스 집합의 부분집합이 있는지 확인한다.
      b. 예를 들어, (0, 1)은 (0)을 포함하기 때문에 최소성을 만족하지 않는다.
      c. 부분집합에 해당하지 않으면 answer 배열에 해당 인덱스 집합을 더해준다.

 

💻  풀이

from itertools import combinations

def solution(relation):
    
    # 가능한 인덱스 조합
    index_combination = []
    for r in range(1, len(relation[0]) + 1):
        index_combination.extend(combinations(range(len(relation[0])), r))
        
    answer = []
    for comb in index_combination:
        
        # 해당 인덱스를 사용한 실제 조합
        tmp1 = []
        for r in relation:
            tmp2 = []
            for c in comb:
                tmp2.append(r[c])
            
            # 이후에 2차원 중복제거를 위해 tuple로 변환 후 append
            tmp1.append(tuple(tmp2))
        
        # 유일성 확인
        if len(set(tmp1)) == len(relation):
            # 최소성 확인
            check = True
            for a in answer:
                if set(a).issubset(comb):
                    check = False
                    break
        
            if check: answer.append(comb)
    return len(answer)

 

🧩  포인트

- 2차원 리스트를 중복제거 하기 위해서는 tuple을 사용해 1차원 리스트로 만들어 주고 set을 사용한다.
- tuple은 중복 제거가 되지 않는다.

❓  문제

2018 KAKAO BLIND RECRUITMENT - [3차] 방금그곡

 

🛎️  아이디어

1. musicinfos 배열에서 가져온 데이터를 "," 기준으로 분리한다.

2. sheet(악보정보)를 list를 사용해 문자열을 분리하고 만약 분리된 문자열이 #이면 바로 앞 문자에 붙여준다.
      a. "AB#C" -> ["A", "B", "#", "C"] -> ["A", "B#", "#", "C"]

3. sheet 배열에서 '#'를 삭제해준다.
      a. ["A", "B#", "#", "C"] -> ["A", "B#", "C"]

4. 시작 시간과 종료 시간은 ":" 기준으로 시/분으로 분리한다.

5. 시와 분끼리 계산해주고 실제 재생된 Melody를 만들어준다.

6. 해당 멜로디에 네오가 기억하는 부분이 있는지 확인한다.
      a. 샾이 붙은 데이터는 미리 제거한다.
            ㄱ. ABC#D에는 ABC와 ABC# 모두 포함될 수 있다.
            ㄴ. 네오가 기억하는 부분에 #를 더한 ABC#과 ABC##을 찾아서 미리 제거한다.

7. 네오가 기억하는 부분이 포함되면 match_list에 append해준다.

8. 재생시간 기준으로 역순 정렬한다. 만약 match_list가 비어있다면 (None)을 반환한다.

 

💻  풀이

# 음악이 시작한 시각, 끝난 시각, 음악 제목, 악보 정보
def solution(m, musicinfos):
    match_list = []

    for musicinfo in musicinfos:
        start_time, end_time, title, sheet = musicinfo.split(",")

        # sheet 변경
        #1. 모든 문자열 분리 및 #붙이기
        sheet = list(sheet)
        for idx, item in enumerate(sheet):
            if item == "#":
                sheet[idx - 1] += "#"

        # 샾 제거
        sheet = [i for i in sheet if i != "#"]

        # 분, 초 분리
        start_hour, start_minute = start_time.split(":")
        end_hour, end_minute = end_time.split(":")

        # 재생 시간 계산
        sub_hour = int(end_hour) - int(start_hour)
        sub_minute = int(end_minute) - int(start_minute)
        play_time = 60 * sub_hour + sub_minute

        melody = sheet * (play_time // len(sheet)) + sheet[:play_time % len(sheet)]

        # 샾이 붙은 데이터 제거
        # ABC#D에는 ABC와 ABC# 모두 포함될 수 있음. 따라서 ABC#과 ABC##을 찾아서 미리 없앰.
        check_melody = ''.join(melody).replace(m + "#", '')
        if m in check_melody:
            match_list.append({"playTime": play_time,
                               "title": title})

    match_list = sorted(match_list, key= lambda x: x["playTime"], reverse= True)
    if match_list == []:
        return "(None)"
    else:
        return match_list[0]["title"]

❓  문제

Summer/Winter Coding(~2018) - 스킬트리

 

 

🛎️  아이디어

1. skill_trees 배열에서 하나씩 꺼내온다.

2. 해당 배열에서 find를 사용하여 skill의 각각의 원소에 해당하는 인덱스를 가져온다.

3. 만약 find의 리턴 값이 -1이라면 (해당 배열에 값이 없는 경우) skills의 길이를 넣어준다.
    a. -1이 앞에 있는 경우 미통과이기 때문에 순서를 뒤바꿀 수 있는 큰 값을 넣어주는 것이다.

4. 정렬했을 때 순서가 바뀌지 않는다면 통과!

 

💻  풀이

def solution(skill, skill_trees):
    answer = 0

    for skills in skill_trees:
        token_index_list = list(map(lambda x: skills.find(x), skill))
        token_index_list = list(map(lambda x: len(skills) if x == -1 else x, token_index_list))
        if token_index_list == sorted(token_index_list):
            answer += 1

    return answer

    print(solution("CBD", ["BACDE", "CBADF", "AECB", "BDA"]))

"""
token_index_list 결과가 다음과 같으면,

[2, 0, 3] -> 미통과
[0, 1, 3] -> 통과
[2, 3, -1] -> 통과
[-1, 0, 1] -> 미통과

-1이 있는 두 가지를 구별할 방법은 -1인 경우 큰 값을 넣어주기!
"""

 📌 근거리 네트워트 (LAN, Local Area Network)

  • 범위가 건물 안이나 특정지역인 네트워크이다.
  • 유선 케이블, 적외선 링크, 무선 송수신기 등을 이용하여 통신한다.
  • 한 건물 또는 인접한 건물군 내에 있는 네트워크는 하나의 LAN으로 간주되며 집이나 빌딩 안에 있는 사무실 등 지리적으로 제한된 곳에서 컴퓨터와 프린터, 스캐너 등을 연결할 수 있는 네트워크이다.
  • 서로 다른 LAN을 연결하여 사용할 수 있다.

 

 📌 도시 지역 네트워크 (MAN, Metropolitan Area Network)

  • LAN보다 넓은 영역이고 WAN보다 작은 영역을 커버한다.
  • 떨어져 있지만 동일하거나 다른 도시에 상주하는 두 대 이상의 컴퓨터를 연결한다.
  • 예시
    고객에게 고속 DSL 회선을 제공할 수 있는 회사의 일부 네트워크나 케이블 TV 네트워크가 있다.
    지역 또는 도시 내에 위치한 다양한 경찰서를 서로 연결하는 데 사용할 수 있다. 경찰관은 인터넷 연결 없이 쉽게 통신할 수 있고 중요한 데이터와 긴급 메시지를 네트워크를 통해 신속하게 전달할 수 있다.

 

 📌 광역 네트워크 (WAN, Wide Area Network)

  • 두 개 이상의 근거리 네트워크를 넓은 지역에 걸쳐 연결하는 것이다.
  • 근거리 네트워크에 포함되지 않은 멀리 떨어진 컴퓨터 사이에서도 광역 네트워크를 이용하여 서로 통신할 수 있다.
  • LAN보다 오류 발생 확률이 크고, 속도는 느리며, 비용은 많이 든다.
  • 예시
    어떤 기업의 본사는 서울에 있고 생산 공장은 지방에 있을 수 있다. 이 둘 간에 데이터와 프로그램 등을 공유하려고 기존 전화선에 라우터를 연결하여 광역 네트워크를 구성하기도 한다.

 

 📌 인트라넷 (Intranet)

  • 인터넷에서 사용하는 회선과 여러 기반 기술을 이용하여 구축하는 사설 네트워크이다.
  • 기업에서 내부망, 외부망을 따로 관리하는 경우가 있는데 이러한 경우 내부망이 바로 인트라넷이다.
  • 예시
    각 지방에 분산된 대학 캠퍼스들을 전용회선을 이용하여 네트워크로 연결한다면 지불 비용이 많이 들 것이다. 하지만 인터넷을 이용하면 쉽게 해결할 수 있다.
  • 아무리 멀리 떨어져 있어도 각 지방의 캠퍼스들을 ISP까지만 연결하면 인터넷을 이용하여 저렴한 비용으로 사설 네트워크를 구축할 수 있다.

 

 


이미지 출처

2020 데이터통신 및 네트워크 수업 자료

* 수업시간에 다룬 vagrantfile에 대해 설명한 글입니다.

 

config.vm.box = ?

?에는 vagrant web site에서 사용할 box를 찾아 넣어준다.

예시는 아래와 같다.

vagrant에서 찾은 box


config.vm.provider에는 사용할 provider에 대한 정보를 넣는다.


"forwarded_port"는 포트 포워딩을 뜻한다. (computer의 특정 포트로 들어온 통신을 VM의 포트로 전달하는 것)

해당 코드는 host의 8080 포트로 통신을 시도하면 VM의 80번 포트로 접속시킨다.

ip주소는 따로 지정하지 않았으므로 상관 없다.


우리가 사용하는 컴퓨터의 ip 주소가 여러개이기 때문에 그 중 어떤 ip 주소와 연결된 포트포워딩인지 지정해준다.

따라서 127.0.0.1 ip 주소로 8080 포트가 오면 guest의 8080 포트로 보낸다.

 

+ 여기서 127.0.0.1은 loop back interface인데 여기로 통신하는 이유는 내가 사용한 computer의 network 설정이 제대로 되어있는지 확인하기 위함이다.


private network ip주소를 192.168.33.10으로 지정한다.

 

+ 만약 설정해주지 않으면 DHCP 서버가 자동으로 생성한다.


bridge를 지정한다.

(가상머신이 호스트와 연결되는 방법으로 bridge를 사용할 경우 설정한다. 이 경우에는 host와 같은 레벨의 컴퓨터가 된다.)


가상머신과 호스트 컴퓨터간 폴더를 공유한다.

첫 번째 parameter는 host의 것, 두 번째 parameter는 가상머신의 폴더이다.

 📌 box

VM을 생성할 때 사용할 가상 이미지이다. 즉, 가상머신 이미지로 사용할 수 있도록 초기 설정된 바이너리이다.

box와 vm은 빵틀과 빵 같은 개념인데 VM은 box로 만든 가상의 기계라고 할 수 있다.

box는 아래와 같이 vagrant 웹 페이지에서 리소스들을 볼 수 있다.

https://app.vagrantup.com/boxes/search

 

 📌 provider

provider는 이미지를 사용하여 VM을 시작하는 시스템 소프트웨어이며 가상환경을 제공해주는 공급자로서 provider로 선택할 수 있는 것은 virtual box, vmware, docker 등이 있다.

아래와 같이 provider별 box도 볼 수 있다.

 

이용자가 '재생' 버튼을 누르기 전까지 일어나는 모든 일은 AWS에서 발생하고, 그 때 방영되는 영상 콘텐츠 자체는 CDN에서 만들어진다. CDN은 영상 콘텐츠를 저장하고 이를 클라이언트 기기로 전송한다.

 

넷플릭스는 이를 통해 웹사이트 로드 시간 개선, 대역폭 비용 절감, 콘텐츠 가용성 및 웹사이트 보안 개선 등 네트워크 효율성을 극대화하였다.

 

CDN이 가능했던 이유는 넷플릭스가 사용자에 대한 정보를 알기 때문이었는데, 특히 이를 이용하여 선호도와 위치에 따라 OCA를 배치하여 사용자에게 가까운 콘텐츠를 제공했던 것이다.

+ Recent posts