sw사관학교정글/회고 및 생각정리

[week02] WIL - 2주차 회고 및 배운내용 정리

D cron 2021. 11. 21. 23:18

📷 회고

2주차에는 조원 형의 추천으로 문제들의 속도, 메모리, 코드길이를 적어서 google sheet에 올렸다. 이 방법을 사용하니까 더 속도를 높이려면 어떻게 해야하는지 상대방의 코드를 참고할 수 있어서 좋았다. 각자의 코드는 github repository를 각자 파서 올리고 그 주소를 공유해주는 식으로 볼 수 있게 했다. 추이를 살펴보니 같은 문제에서 속도와 메모리는 반비례관계가 있는 듯 했다. 속도를 빠르게 하기 위해 여러 작업들을 추가할수록 메모리 사용이 늘어나는 것 같다.

 

각자 풀다가 이렇게 가다가는 다 못풀 것 같아서 회의를 통해 진도를 맞추고 1시간 고민, 못풀면 1시간 답보고 이해, 그래도 이해못하면 1시간동안 서로 알려주는 식으로 진행했다.(1-1-1) 1주차와 비슷하게 혼자 힘으로 풀려고 했으면 다 못풀었을 것이다. 팀원들과 함께 문제를 3시간 안에 계속 해결해 나가서 끝까지 다 볼 수 있었던 것 같다.

 

같은 조 형이 백준 문제풀어본 것을 내가 어떻게 접근했는지, 왜 이렇게 접근해야 하는지, 내 실수들 등을 정리하면 조금 남는게 있다고 해서 시도해 보았다. 또 1주일에 한번 회고가 아니더라도 블로그에 가끔 글을 쓰려고 노력했다.

 

여기서는 서로 잘 몰라도 일단 가서 물어보면 친절하게 알려주는 신기한 분위기가 형성되어 있다. 내가 무작정 가서 질문하고 나서 다시 자리로 돌아갈 때, 물어봐주신 덕분에 자신도 정리가 되었다고 하셔서 나도 그렇게 말할 수 있는 사람이 되었으면 좋겠다고 생각했다.

📗 배운 내용 정리

  • 스택
    • 스택(stack)은 데이터를 임시 저장할 때 사용하는 자료구조로, 데이터의 입력과 출력 순서는 후입선출(Last In First Out) 구조이다.
    • 스택 사용 예시
    • stack = []
      stack.append(1)
      stack.append(2)
      stack.append(3)
      stack.pop()
      # 3
      print(stack)
      # [1,2]
  • 큐는 가장 먼저 넣은 데이터를 가장 먼저 꺼내는 선입선출(First In First Out) 구조이다.
    • 큐 사용 예시
    • from collections import deque
      queue = deque([1,2,3])
      queue.appendleft(4)
      # deque[4,1,2,3]
      queue.popleft()
      # 4
      print(queue)
      # deque[1,2,3]
    • appendleft(x)와 popleft(x) 메서드는 모두 O(1)의 시간복잡도를 가지기 때문에 list 자료구조의 pop(0)(시간복잡도 O(N))보다 성능이 뛰어나다.
    • 힙은 '부모의 값이 자식의 값보다 항상크다'는 조건을 만족하는 완전 이진 트리이다. 이때 부모의 값이 자식의 값보다 항상 작아도 힙이라고 한다.
    • 힙은 형제의 대소관계가 정해져 있지 않으므로 부분 순서 트리라고도 한다.
    • 인큐할 때는 데이터에 우선순위를 부여하여 추가하고, 디큐할때 우선순위가 가장 높은 데이터를 꺼내는 방식이다. 파이썬에서 우선순위를 부여하는 큐는 heapq 모듈에서 제공한다. (참고로 내장함수로 구현하면 최소힙이 됨)
    • 힙을 사용하기 위해서는 heapq 모듈을 임포트 해줘야 한다.
      • import heapq
        # 힙 생성하기
        heap = [] # heapq는 리스트를 최소 힙처럼 다룰 수 있도록 도와주기 때문에 리스트를 사용
      • 인큐는 heapq.heappush(heap,data)로 수행
      • 디큐는 heapq.heappop(heap)으로 수행
      • heap = []
        heapq.heappush(heap,1)
        # [1]
        -----------------------
        heap = []
        heapq.heappush(heap,4) #[4]
        heapq.heappush(heap,1) #[1, 4]
        heapq.heappush(heap,7) #[1, 4, 7]
        heapq.heappush(heap,3) #[1, 3, 7, 4] -> 최소 힙 형태로 계속 유지됨
    • heap 원소 최솟값 얻기 
      • heap = [3,2,1]
        heapq.heapify(heap) # heap 리스트 자체를 최소힙 자료구조로 변환 O(NlogN)
        print(heap[0])     # 1
        # 주의할 점은 두번째로 작은 원소를 얻으려면 바로 heap[1]을 통해 접근하면 안되고,
        # 반드시 heappop()을 통해 가장 작은 원소를 삭제 후에 heap[0]을 통해 최소값에 접근!
        # heap 구조는  
        ----------------------------------------
        # heapq pop으로 최솟값 얻기
        heap = [3,2,1]
        heapq.heapify(heap) # heapify 함수가 실행되면 비어있는 리스트를 생성한 후
        # heappush() 함수로 원소를 하나씩 추가한 효과가 난다. 따라서 heapify()함수의
        # 성능은 인자로 넘기는 리스트의 원소수에 비례한다. O(N)
        print(heapq.heappop(heap)) # 1
        print(heap) # [2,3]
    • 최대 힙 구현하기
      • 힙에 튜플을 원소로 추가하거나 삭제하면, 튜플 내에서 맨 앞에 있는 값을 기준으로 최소 힙이 구성된다. 따라서, 최대 힙을 만드려면 각 값에 대한 우선 순위를 구한 후, (우선 순위, 값) 구조의 튜플을 힙에 추가하거나 삭제하면 된다. 그리고 힙에서 값을 읽어올 때는 각 튜플에서 인덱스 1에 있는 값을 취하면 된다.
      • import heapq
        
        nums = [4, 1, 7, 3, 8, 5]
        heap = []
        
        for num in nums:
          heapq.heappush(heap, (-num, num))  # (우선 순위, 값)
        
        while heap:
          print(heapq.heappop(heap)[1])  # index 1
    • 힙의 시간복잡도
      • heapify의 시간복잡도: O(N)
      • heap 구조 안에서 삭제, 추가해서 다시 heap 구조 만드는 것 → O(logN)
      • 왜냐하면 heap은 이진트리 구조이므로 한번 들어갈때마다 반토막씩 날라간다.
  • self 이해하기
    • 자바스크립트에서의 this와 느낌이 비슷한 것 같다.
    • self는 class instance다.
    • class(클래스)란 무엇인가?
      • 클래스는 똑같은 무엇인가를 계속해서 만들어낼 수 있는 설계, 틀과 같은 것이다.(자동차 설계도)
    • 객체(Object)란 무엇인가?
      • 객체(Object)는 클래스에 의해서 만들어진 물건, 실체를 뜻한다.(자동차)
        • 객체를 만들면 다른 객체와는 16진수의 값으로 구별하고 이 값을 래퍼런스 값이라고 한다. 이 값을 통해 메모리에 어느 곳에 저장되었는지 알려준다.
    • instance(인스턴스)는 무엇인가?
      • 클래스에 의해서 만들어진 객체를 인스턴스(instance)라고도 한다.
      • 객체와 인스턴스의 차이는 무엇인가? 인스턴스는 특정 객체가 어떤 클래스의 객체인지를 관계 위주로 설명할 때 쓴다. ex) '트럭은 인스턴스'보다는 '트럭은 객체', '트럭은 자동차의 객체'보다는 '트럭은 자동차의 인스턴스'
      • 인스턴스는 메모리에 할당된다. 객체가 메모리에 할당되어 실제 사용될 때 인스턴스라고 한다. 즉 인스턴스는 객체에 포함된다고 볼 수 있다.

💻 코치님 조언

반복해서 말씀드리지만 알고리즘 문제의 풀이 방법은 한가지가 아닙니다. (이 문제의 leetcode solution에서도 풀이 방법을 5가지를 제시합니다.)
여러가지 방법 중에서 한 가지라도 풀이 방법을 찾아낼 수 있으면 됩니다. 여러 방법을 찾고 어느게 더 좋은지를 비교할 수 있으면 더 좋겠죠. 그렇지만 풀 수 있는 문제의 종류를 늘리는 게 먼저입니다. 어떤 문제가 주어졌을 때 풀이 방법을 한가지라도 찾는 능력을 기르는 것이 이번 과정의 의도임을 이해해 주시면 감사하겠습니다.
꼭 sheet에 적힌, "다루는 주제"의 방법대로 풀어야 한다는 것은 아닙니다. 어떻게든 풀면 됩니다. 비슷한 문제가 나왔을 때 풀 수 있으면 됩니다.

🚀 운영진 면담(내 질문 + 기억에 남는 다른 분들 질문)

Q. 창업을 하면 성공할 확률은 매우 적고 망하면 직원들도 직장을 잃게 되는건데 직원들의 생계에 대한 책임감이 엄청 클 것 같은데 그런 중압감을 어떻게 다루시는지 궁금합니다.
A.
[장병규의 스타트업 한국] 책을 읽어보면 거기에 생각이 담겨있다. 
여기서 창업을 한 사람이 두명이나 있기 때문에 물어보고 싶을 수 있다. 그러나 지금은 키워드만 적어 놓고 정글 안에서는 개발자가 되기 위한 공부에 올인했으면 좋겠다. 5개월 동안 그것만 집중해도 쉽지 않다. 정글이 끝나고 바로 창업할 수는 없다. 적어도 개발자가 되어서 회사에서 2년정도 빡세게 일하고 난 뒤에 생각해도 늦지 않다. 지금은 창업관련된 책 보지 말고 차라리 그 시간에 잠을 더 자라.
Q. 컴퓨터 시스템책 읽기, 블로그 정리, 알고리즘 풀이, 운동, 알고리즘 공부 등 할것이 정말 많은데 여기서 우선순위를 무엇으로 두어야 하나요?
A.
우리가 우선순위를 정해줄 수 있다. 그럼 1~2주일은 효율적일 것이다. 그러나 우리의 목표는 스스로 성장할 수 있는 근육을 만들어주는 것이다. 지금 당장은 비효율적일 수 있으나, 시행착오를 계속 겪으면서 (새로운 방법을 시도해 보고) 자신에게 맞는 공부법과 우선순위를 찾아나가라. 그게 장기적으로 봤을 때 더 도움이 될 것이다.
알고리즘 주차에서는 주어지는 모든 과제를 풀어보는 것을 1순위로 두고 나머지는 스스로 정해보아라. 여기서는 지식을 배운다기보다는 배우는 방법을 학습하는 과정이라고 생각해라.
Q. 하루하루 최선을 다하고 있는데 제 성장을 측정할 방법이 없습니다. 5개월이 지난 뒤에 제가 과연 기업들이 보기에 뽑고싶은 개발자가 될 실력을 갖출 수 있을까요?
A.
그런 마음을 가지는 거 120% 공감한다. 크래프톤에서도 신작 게임을 출시할 때 이게 얼마나 잘 될지 측정하고 싶다. 그러나 게임은 세상에 나오기 전까지는 얼마나 잘 될지 예측이 불가능하다. 그러니까 불가능한걸 예측하려고 하는 건 바보같은 짓이다. 마찬가지로 5개월 뒤에 여러분이 어떻게 될지는 아무도 알 수가 없다. 불안한건 충분히 이해하지만 취업이 가능한 실력인지 측정할 수 있는 기준같은건 없다. 그러니까 고민하지말고 매일 충실히 사는것이 정답에 가깝다. 그리고 자신을 믿어봐라. 

참고자료

Do it! 자료구조와 함께 배우는 알고리즘 입문 파이썬 편

https://docs.python.org/ko/3/tutorial/modules.html

https://www.itple.co.kr/entry/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B0%9D%EC%B2%B4-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0

https://www.daleseo.com/python-queue/

https://www.daleseo.com/python-heapq/