알고리즘 문제를 풀고나서 설명을 할때 꽤 자주 면접에 들어온 엔지니어들이 해당 코드의 시간 복잡도나 공간 복잡도에 대해서 물어볼때가 있다. 그래서 시간 복잡도는 무엇인지 그리고 공간 복잡도는 무엇이고 계산을 어떻게 하는지 적어보려고 한다. 

 

1. 시간  복잡도란?

코드를 작성했다고 치자. 해당 코드의 실행시간을 수학적으로 풀어쓴 것이라고 보면 된다. 좀더 정확히 말해서, 코드의 실행 시간이 얼마나 걸릴것인지를 시간 복잡도라고 한다. 입력 크기 n에 따라 알고리즘이 실행되는 데 필요한 연산 횟수이다. 

보통은 최악의 경우를 기준으로 분석하고 빅오 표기법을 사용한다.

 

2. 시간 복잡도 계산법

- 코드에서 반복문과 연산 횟수를 기준으로 연산량을 세어보면된다. 

 

int getFisrtElement(int arr[], int n) {
	return arr[0]; // 항상 0번째 요소를 반환
}

만약 위처럼 단순히 배열이 들어오면 0번째 요소를 반환하는 함수가 있다고 가정한다면. 해당 함수의 실행시간은 배열의 길이에 상관없이 항상 한번만 연산을 하면 된다. 따라서 위 함수의 시간 복잡도는 O(1)이다. 이는 "상수 시간"으로 읽기도 한다. 

 

코드 상에서는 반복문을 실행할 일이 많다. for문, while문들이 있는데 이 경우에도 총 연산횟수로 계산하면된다. 

int sumArray(int arr[], int n) {
    int sum = 0;
    for (int i = 0; i < n; i++) { // n번 반복
        sum += arr[i];
    }
    return sum;
}

반복문이 n번 실행되기 때문에 O(n)으로 볼 수 있다. 이럴 경우 이 sumArray함수의 시간 복잡도는 n에 선형적으로 비례한다고 말할 수 있다. 그리고 만약 for문 안에 for문이 하나 더 있다면 n의 제곱이 된다.

 

int binarySearch(int arr[], int n, int target) {
    int left = 0, right = n - 1;
    while (left <= right) {
        int mid = (left + right) / 2;
        if (arr[mid] == target)
            return mid;
        else if (arr[mid] < target)
            left = mid + 1;
        else
            right = mid - 1;
    }
    return -1;
}

Binary Search(이진 탐색)를 할 경우에는 범위가 매번 절반으로 줄어든다. 따라서 이 경우 시간은 log n으로 표기한다.

3. 공간 복잡도란?

입력 크기 n에 따라 알고리즘이 사용하는 메모리 공간의 양을 나타낸다. 보통 사용하는 변수, 배열, 재귀 호출 스택 등을 기준으로 계산한다. 

4.  공간 복잡도 계산법

고정 공간, 가변 공간으로 나눠서 계산할 수 있는데 고정 공간이란 입력 크기와 무관하게 항상 사용되는 공간이고 가변 공간은 입력 크기에 따라 변하는 공간을 말한다. 

 

int factorial(int n) {
    if (n == 0) return 1;
    return n * factorial(n - 1); // 재귀 호출
}

 

재귀 호출이 n에서 0까지 호출 스택에 쌓이기 때문에 O(n) 공간을 사용한다. 

C++로 Array, Structure, Pointer, Function 관련해서 정리를 해보았다.

Array란?

배열(Array)은 하나의 자료구조로 "연속적인" 자료구조이다. 그게 무슨 말이냐 하면, 메모리에 저장될때 순서대로 물리적인 공간 상에 저장된다는 말이다.

예를 들어..

int foo [5] = { 16, 2, 77, 40, 12071 }; // 초기화

16, 2, 77, 40, 12071은 모두 메모리상에 실제로 순서대로 저장된다. 하지만 이건 언어들에 따라 다르다. 아마 Python같은 언어들은 이미 List같은 자료형들이 Linked List같은 형태로 되어있는걸로 알고있다. Linked List는 참고로 하나의 자료구조로 각 요소들이 주소로 연결되어있는 연속적인 자료구조이다.

C++에서 Array의 요소에 접근할때는 index로 접근이 가능하다, 다른 언어들처럼.

foo[1] // 16

초기화하지 않은 요소들은 모두 0으로 초기화된다


int main() {

    int foo[5] = {1,2,3};

    for(int i : foo)
    {
        cout<<i<<endl;
    }

    return 0;
}

위 코드의 출력화면은 다음과 같다.

1
2
3
0
0

Structure란?

영어로는 Structure, 한국어로는 구조체이다.

C언어에서는 Class가 없기 때문에 구조체로 객체와 비슷하게 만들어서 사용할 수 있는데 C++에서도 C언어의 기능을 사용할 수 있다. struct라는 키워드를 사용해서 선언한다.

struct Circle
{
    double x; // 좌표점 x
    double y; // 좌표점 y
    double radius; // 반지름
};

Circle이라고 하는 구조체의 예시.

그럼 구조체를 정의했으니 구조체 하나를 선언후 값들을 출력해보자.

int main() {

    struct Circle c = { 0, 0, 5}; // 선언과 동시 초기화

    cout<<c.x<<endl<<c.y<<endl<<c.radius<<endl;

    return 0;
}

출력 결과는 다음과 같다.

0
0
5

만약 우리가 Circle c의 area값을 출력하고 싶다면 3.14를 곱해서 할 수 있다.

cout<<c.radius*c.radius*3.14<<endl;

Pointer란?

포인터라는 개념은 C,C++에서 가장 중요한 개념이다. 사실 이걸 배우기 위해서 Reference라는 개념도 배우고 문자열, Stack, Heap이라고 하는 단어들을 알고 있어야 한다. 그래서 혹시 용어들을 모른다면 반드시 Reference, Stack, Heap에 대해서 검색하고 찾아봐라.

포인터란 주소 변수로 메모리 주소에 들어가있는 실제 데이터를 저장하지 않는다. 즉, 메모리 주소만 저장하는 변수이다.
포인터는 데이터를 직접적으로 접근하지 않을때 사용하고 또한 유용하다. 특히, Heap영역에 있는 데이터에 접근할때 포인터가 사용된다.


int main() {

    int num1 = 100;
    int arr[5] = {10, 20, 30, 40, 50};

    int *p1; // p1라고 하는 포인터 변수 선언
    int *p2; // p2 포인터 변수 선언

    p1 = arr; // arr변수의 주소를 p1에 할당
    p2 = &num1; // num1의 주소를 p2에 할당

    cout<<p1<<endl; // arr의 첫번째 메모리 주소가 출력됨.
    return 0;
}

위의 예시에서 arr&를 앞에 붙이지 않았는데 이건 배열의 경우 arr가 이미 주소를 담고 있기 때문에 그렇다. 그래서 p2에 num1의 주소를 할당할때는 int형 num1변수의 주소를 참조(reference)하기 위해서 &(주소연산자)를 넣어준다.

결국 메인메모리 바깥에 접근하기 위해서는 포인터를 사용할 수 밖에 없다.

구조체와 포인터


 struct Rectangle r = {10, 5};
 struct Rectangle *p;

 p = &r; // 0x7ffd1fdb4970 메모리 주소
 r.length = 15;
 p->breadth = 20;

 cout<<p<<endl<<p->length<<endl<<p->breadth<<endl;

위의 출력 결과는

0x7ffd1fdb4970
15
20

이다

메모리 접근 -> 문법은 익숙해져놓는게 좋다.

Function

함수는 가장 기본적인 형태의 모듈로 어떠한 값을 return하는 구조이다. 코드를 작은 단위로 쪼갤때 사용하고 function을 사용해서 각 코드의 기능을 작게 나누는건 좋은 코딩습관이다.


int add(int a, int b) {
    return a + b;
}

int main() {

    int x = 5;
    int y = 10;

    printf("%d", add(x, y));

    return 0;

}

이번에 플로리다 여행을 오면서 디즈니랑 유니버셜 중에 어느걸 할까 고민을 많이 했는데

어벤저스랑 디즈니 캐릭터보다는 유니버셜의 해리포터 관련 시설들을 더 보고 싶어서 유니버셜 티켓으로 구매해서 오게되었다... 사실 한사람당 비용이 꽤나 들기 때문에 버짓상 못 한것도 있다. 

 

 

유니버셜 스튜디오 올랜도는 세계적으로 유명한 테마파크 중 하나이다. 영화와 테마를 중심으로 다양한 어트랙션과 쇼를 즐길 수 있다. 

1. 유니버셜 스튜디오 올랜도 구성

유니버셜 스튜디오 올랜도는 두 개의 주요 테마파크와 하나의 워터파크로 구성되어 있다

유니버셜 스튜디오 플로리다, 들어가서 오른쪽으로 가야 나온다. 첫날은 여기를 갔다.

 

    • 주요 어트랙션:
      • 해리 포터의 다이아곤 앨리 (Diagon Alley): 해리 포터 테마의 쇼핑과 놀이기구를 즐길 수 있다. 그린고트 은행도 볼 수 있는데 7편에 나오는 용이 올라가있다. 
      • 트랜스포머: 더 라이드 3D (Transformers: The Ride-3D).
      • 미니언 메이헴 (Despicable Me Minion Mayhem).유니버셜 스튜디오 플로리다 (Universal Studios Florida)
  1. 아일랜드 오브 어드벤처 (Islands of Adventure)
    1. 주요 어트랙션:
      • 해리 포터의 호그스미드 (Hogsmeade): 호그와트 익스프레스와 포비든 저니를 체험할 수 있다.
      • 쥬라기 공원 리버 어드벤처 (Jurassic Park River Adventure).
      • 더 어메이징 스파이더맨 (The Amazing Adventures of Spider-Man).
  2. 유니버셜 볼케이노 베이 (Volcano Bay)
    • 유니버셜 스튜디오의 워터파크로 물놀이를 즐길 수 있다.

2. 티켓 정보 및 가격

  • 1일 티켓
    • 1개 파크: 약 $109부터 시작한다 (성수기에는 더 비쌀 수 있다).
    • 2개 파크: 약 $164부터 시작한다 (파크 투 파크 옵션 포함).
  • 2일 이상 티켓
    • 2일권: 약 $213부터 시작한다 (1개 파크 기준).
    • 파크 투 파크 옵션 추가 시 추가 비용이 발생한다.
  • 볼케이노 베이 포함 티켓
    • 약 $70부터 추가된다.
  • 익스프레스 패스
    • 일반적으로 1인당 $80에서 $200 사이 제가 갔을때는 인당 $100 여서 따로 하진 않았어요. 
    • 유니버설 익스프레스 패스 (Universal Express Pass): 각 어트랙션을 한 번씩 빠르게 이용할 수 있는 패스, 있으면 놀이기구 빨리 탈 수 있어요.
    • 유니버설 익스프레스 언리미티드 패스 (Universal Express Unlimited Pass): 어트랙션을 무제한으로 빠르게 이용할 수 있는 패스입니다.

 

 

티켓 구매 방법

  • 유니버셜 공식 홈페이지에서 구매할 수 있다.
  • 여행사 패키지 또는 호텔과 연계된 할인 티켓을 이용할 수 있다.
  • Costco 등 멤버십 할인도 제공된다.

저렴하게 구매하는 팁

  • 할인 사이트 (Undercover Tourist, Orlando Fun Tickets)를 활용할 수 있다.
  • 비성수기에 예약하면 더 저렴하다. 11월은 비수기라 그나마 티켓이 싼 편이었다. 
  • 멀티데이 패스를 구매하면 하루당 가격이 저렴하다. 따라서 2데이 패스를 구매후 각각 하루씩 가보는걸 추천한다. 

3. 주차장 및 주차비

  • 주차장 종류
    • 일반 주차: $30이다.
    • 프리퍼드 주차 (파크 입구에 더 가까움): $50이다.
    • 발레 파킹: $70이다.

4. 운영 시간

  • 일반적으로 오전 9시~오후 8시까지 운영한다 (시즌과 날씨에 따라 다를 수 있다).
  • 공식 웹사이트나 앱에서 정확한 운영 시간을 확인할 수 있다.

5. 방문 준비물

  • 필수 아이템:
    • 오래 걸어도 편안한 운동화
    • 물병
    • 작은 백팩 하나 정도(중간중간 가방을 못갖고 타는 것들이 있는데 밖에 있는 락에 넣어야한다. 
    • 간단한 간식
  • 앱 설치:
    • 유니버셜 앱을 설치해 어트랙션 대기 시간을 확인하고 모바일 오더 기능을 사용할 수 있다.

6. 꿀팁

  • Early Park Admission: 유니버셜 호텔에 머물면 일반 입장객보다 1시간 먼저 입장할 수 있다.
  • 유니버셜 앱을 깔고 핸드폰으로 티켓을 가지고 다니는걸 추천한다. 결제카드도 연동해놓으면 파크 내에서 음식주문할때 편하다.
  • 해리 포터 팬들을 위한 팁:
    • 다이아곤 앨리와 호그스미드를 연결하는 호그와트 익스프레스를 타려면 파크 투 파크 티켓이 필요하다.
    • 올리밴더스에서 마법 지팡이 체험을 할 수 있다 (대기 시간이 길 수 있다). 
  • 굉장히 규모가 크기 때문에, 운동화, 물통을 챙겨가면 좋다. 물은 계속해서 채울 수 있다.
  • 비 오는 날:
    • 비가 와도 어트랙션은 대부분 운영된다.
    • 우비 또는 방수 재킷을 준비한다.

 

전체적인 피드백

1박2일 일정으로 갔다왔는데 숙소는 근처에 있는 에어비앤비로 잡았다. 에어비앤비에서는 차로 10분정도 거리여서 매일 아침 8시반 정도에 출발해서 개장 전에 앞에 가 있었다. 

개장 전 한산한 모습

 

우리는 11월에 월요일, 화요일 일정이어서 사람이 정말 없었다. 두개 모두 가보면서 느낀건, 만약 하나만 가야할때는 상황에 따라 다르겠지만 아이들을 동반했고 해리포터를 좋아한다면 아일랜드 오브 어드벤처를 추천한다. 더 스릴있는 롤러코스터도 많고 아이들이 즐길거리가 대체적으로 좀 더 많은 것 같다.

 

 

유니버셜 스튜디오 LA랑 올랜도를 둘다 가보고 느낀건 둘다 가족여행, 특히 아이들이 있다면 오기 좋은 것 같다. 올랜도 디즈니월드도 있고 올랜도, 플로리다가 미국 내에서 피서지이기 때문에 가족끼리 즐길거리가 굉장히 많고 케네디 스페이스 센터도 있어서 함께 돌아보면 가족과 함께 좋은 시간을 보낼 수 있을 것 같다. 

 

+ Recent posts