본문 바로가기
알고리즘

[Do it 알고리즘 코딩테스트] JAVA

by yuuuuna0 2023. 7. 12.

시간복잡도

1. 시간복잡도 : 알고리즘 선택의 기준 / 주어진 문제를 해결하기 위한 연산 횟수

  1) 유형 : 빅오메가_최선일 때(i=0 -->1번) / 빅세타_보통일 때(i=50 --> N/2번) / 빅오_최악일 때(i=99 --> N번)

 =====> 시간복잡도 코딩 테스트는 최악의 케이스를 염두에 두는 것 -> 빅오일 때를 기준으로 수행시간을 계산해야 함!!

 

본인이 짠 코드의 시간복잡도에 대해서 알아두는 것이 좋다.

 

※연산횟수 = 알고리즘 시간 복잡고 X 데이터의 크기

(버블정렬= N^2 / 병합정렬 = NlogN)

 

시간복잡도 도출 기준 

1) 상수는 시간 복잡도 계산에서 제외한다   -> N이나 3N이나 똑같다

2) 가장 많이 중첩된 반복문의 수행 횟수가 시간 복잡도의 기준이 된다. -> 이중포문으로 시간복잡도가 N^2이 되면 10개의 일반포문이 추가되어도 N^2이다.

 

맞는 알고리즘 -> 시간초과 ==> 로직이 효율적으로 짜여있는지를 확인

 

1. 알맞은 알고리즘 선택 기준 2. 비효율적인 로직 찾아서 효율적으로 바꾸기(중첩문을 확인)

 

 

디버깅

1. 디버깅 --> 논리오류 잡는데 도움을 주는 스킬

 

오류 주의

** 변수 초기화 위치

** 자료형은 처음부터 long형으로 선언하자! --> 디버깅시 변수값이 음수가 나오면 범위를 초과한 것

 

 

자료구조

(1) 배열과 리스트

배열: 연속공간에 값이 채워져 있는 형태의 자료구조 / 인덱스를 통해 참조할 수 있음 --> A[3] / 값을 삽입하거나 삭제하려면 주변 값을 이동시키는 과정이 필요 / 배열 크기 한번 선언하면 변경할 수 없다.

리스트: 값과 포인터를 묶은 노드라는 것을 포인터로 연결한 자료구조 / 인덱스가 없어서 head포인트 순서대로 접근해야 함 -> 접근 속도가 느리다 / 데이터 삽입&삭제 연산속도 빠르다 / 선언시 크기를 지정하지 않아도 된다.  리스트는 크기가 정해져 있지 않다. / 배열보다 구조가 복잡

 ==> 실제 코딩테스트: 크기 픽스 or 데이터 접근 --> 배열 사용 / 크기가 변하는 데이터 or  데이터 삽입&삭제 많은 경우 -> 리스트(ArrayList,LinkedList) 사용

 

(2) 구간합

합 배열을 이용해서 시간복잡도를 줄이기 위해 사용하는 특수한 목적의 알고리즘

i 에서 j까지의 구간 합 = S[j] - S[i-1]

 

(3) 스택과 큐

스택 : 삽입과 삭제가 한 쪽에서만 일어남(top부분에서만 연산이 일어남) --> 후입선출 / 깊이우선탐색, 백트래킹 종류, 재귀함수 알고리즘 원리

      - top : 삽입과 삭제가 일어나는 위치

      - push : top 위치에 데이터 삽입

      - pop : top 위치에 있는 데이터를 삭제하고 확인

      - peek : top 위치에 있는 데이터를 확인 

큐 : 삽입과 삭제가 양방향에서 일어남 -> 선입선출 / 너비우선탐색, 

      - rear : 큐에서 가장 끝 데이터 -> 삽입 부분

      - front : 큐에서 가장 앞의 데이터  -> 삭제 부분

      - add : rear 위치에 데이터 삽입

      - poll : front 위치에 있는 데이터를 삭제하고 확인

      - peek : front 위치에 있는 데이터를 확인

cf. 우선순위 큐 : 들어간 순서와 상관없이 우선순위가 높은 데이터가 먼저 나오는 자료구조

 

 

정렬 

버블정렬 인접데이터끼리 비교하고 swap연산 수행하며 정렬
선택정렬 가장 크거나 작은 데이터를 찾아서 선택 반복하며 정렬
삽입정렬 대상을 선택 -> 정렬된 영역에서 적절한 위치를 찾아 삽입하며 정렬
퀵정렬 피봇값을 정해 해당 값을 기준으로 정렬
병합정렬 이미 정렬된 부분 집합들을 효율적으로 병합해 전체를 정렬
기수정렬 데이터의 자릿수를 비교하여 정렬

(1) 버블정렬

정렬시간을 오래걸리지만 로직이 단순하고 구현이 쉬움

인접한 데이터의 크기를 비교해 정렬 / 시간복잡도 O(n^2) -> 속도가 느린 편 / 정렬되지 않은 영역 내에서만 루프 실행

** 특정 루프에서 swap이 한번도 발생하지 않았다면 데이터가 모두 정렬되었다는 뜻 -> 프로세스 종료

(2) 선택정렬

최대 or 최소 데이터를 찾아 선택  / 시간복잡도 O(n^2)

(3) 삽입정렬

선택한 데이터를 이미 정렬된 데이터 범위에서 적절한 위치에 삽입시켜 정렬 / 시간복잡도 O(n^2) 

** 이진탐색을 하면 시간복잡도를 줄일 수 있다.

** 데이터 시프트하는데 시간이 오래 걸린다

(4) 병합정렬

분할정복 방식을 사용해 데이터 분할  -> 분할한 집합을 정렬하며 합침 / 시간복잡도 O(NlogN)

한번 의 단계를 진행할 때 n번의 data access가 필요하다.

**2개의 그룹을 병합하는 과정 -> 투 포인터 개념을 사용하여 두 그룹의 포인터 값을 비교한다.

1. 집합으로 분할하는 과정                                                                                      2. 두개의 그룹을 병합하는 과정           

 

탐색

(1) 깊이 우선 탐색 (DFS)

그래프 완전 탐색 기법 중 하나 / 재귀함수로 구현 / 스택 이용 -> LIFO / 시간복잡도 O(V+E)__V:노드수 E:에지 수

재귀함수 이용 -> 스택오버플로 유의! / 그래프는 인접리스트로 표현 / 이미 다녀간 노드는 방문배열을 바탕으로 재삽입하지 않아야 함!

1. DFS를 시작할 노드를 정한 후 사용할 자료구조 초기화하기
2. 스택에서 노드를 꺼낸 후 꺼낸 노드이ㅡ 인접 노드를 다시 스택에 삽입하기
3. 스택 자료구조에 값이 없을 때까지 반복하기