🏃‍♀️ 코테 연습

스터디 1일차

ji-hyun 2021. 6. 17. 04:44

1강 <인터뷰 배열 기초>

sorting의 종류 - heap sort, quick sort, merse sort

 

stable한 알고리즘은 merge sort이 있고, unstable한 알고리즘은 quick sort, heap sort가 있다. (퀵힙은 불안정)

ABC 로 테이블이 있을 때, 정렬한 후에도 ABC 이 순서로 유지된다면 stable 알고리즘이다. (잘못 이해했음. 아래에 부가 설명 참고!)

 

search는 배열을 전부 다 돌아야 하기 때문에 O(n) 정도로 걸린다

binary search -> O(logn)

2차원 다차원 array..

 

 

먼저 정렬 알고리즘이란

컴퓨터 과학과 수학에서 정렬 알고리즘(sorting algorithm)이란 원소들을 번호순이나 사전 순서와 같이 일정한 순서대로 열거하는 알고리즘이다. (출처: 위키피디아)

안정 정렬(Stable Sort)

중복된 키를 순서대로 정렬하는 정렬 알고리즘을 뜻한다.

예를 들어, 다음과 같은 list가 있다고 하자.

list=[1, 7, 3, 5, 4, 7, 9]

이 리스트에서 7이 두번 나온다. 구분을 위해 ()를 이용해 앞은 (1), 뒤는 (2)를 표시하면

list=[1, 7(1), 3, 5, 4, 7(2), 9] 와 같다.

 

이때 이 리스트를 정렬했을 때
(1) list=[1, 3, 4, 5, 7(1), 7(2), 9]
(2) list=[1, 3, 4, 5, 7(2), 7(1), 9]

(1)처럼 나오면 안정(Stable) 정렬, (2)처럼 나오면 불안정(Unstable) 정렬이라고 한다.

 

즉, 정렬을 했을 때 중복된 값들의 순서가 변하지 않으면 안정(Stable) 정렬, 변하면 불안정(Unstable) 정렬인 것이다.

 

<대표적인 알고리즘들>


Stable Sorting 알고리즘은 다음과 같다:

  • Insertion Sort (삽입정렬)
  • Merge Sort
  • Bubble Sort (버블정렬)
  • Counting Sort

Unstable Soring 알고리즘:

  • Selection sort
  • Heap Sort
  • Shell Sort
  • Quick Sort

 

 


 


 


2강 <코딩테스트, 기초, 퀵 정렬>

Quick sort 에는 pivot, partitioning 개념이 있다.

 

9 5 2 3 7 8 4 라는 배열에 대해서 살펴보자.

임의로 5를 pivot 으로 잡아본다.

 

 

pivot 을 정해주고 나머지 element들을 파티셔닝 해주는 것

그 다음 단계는 남은 element들에 대해서 pivot을 정해주고 partioning 반복..

swap을 통해서 Quick sort를 진행해야 한다.

 

 

 

 

[ 9 5 2 3 7 8 4 ]   

▲ 5를 임의로 피벗으로 선정... 5와 맨 끝 4 교체

[ 9 4 2 3 7 8 5 ]   

▲ 5를 기준으로 양 끝 인덱스 비교.. 9의 인덱스는 그대로 있고 오른쪽 인덱스는 (<- 방향) 움직이며 비교..

▲ 3은 5보다 작으므로 3과 9를 교체

[ 3 4 2 9 7 8 5 ]   

▲ 양끝 인덱스 비교하면서 움직이다보면 서로의 인덱스가 역전됨

▲ 9와 5를 교체

[ 3 4 2 5 7 8 9 ] 

▲그 다음 피벗 5를 기준으로 양 옆 2개의 파티션 내부에서 각각을 파티셔닝 해준다 (swap 진행시키기)

[ 2 3 4 5 7 8 9 ]

 

 

 

 

피벗을 정하는 방법은 여러가지가 있다.

1) 임의의 피벗을 정한 후, 마지막 숫자와 교환

2) 마지막 숫자를 피벗으로 선정 (오히려 더 느린 sorting)

3) 피벗 숫자를 잡은 뒤 양쪽에서 인덱스를 잡는 것이 아니라 한쪽에서 인덱스를 잡음

 

 

 

time complexity 와 space complexity ... 

 

 

 

Quick sort 가 가장 빠르게 끝낼 수 있는 방법은 피벗을 가운데 값으로 선정할 때이다.

-> O(nlogn) 으로 best case가 된다.

반대로 worst case는 피벗을 최대값으로 선정할 때 발생되며, time complexity는 O(n^2) 가 걸린다.

 

 

※ 일반적으로 피벗을 맨 끝의 숫자로 정하기보다는 랜덤의 위치의 숫자로 정하거나 가운데 값을 가지는 숫자를 피벗으로 정하게 되는데, 그 이유는 정렬된 배열일 경우가 있기 때문이다.

 

 

Quick sort 의 단점은 ustable sort 였다. 다시 한번 각인하자! stable sort는 merge sort 이다.

 

 

 

partition 이라는 함수는 정렬을 시켜주는 함수이다. 오른쪽에 있는 선생님이 필기하신 그림과 같이 보면,

첫번째 quickSort 함수는 left(4) 와 pivot-1(2) 를 퀵정렬을 하는 것이고,

두번째 quickSort 함수는 pivot+1(9) 와 right(6) 을 퀵정렬 하는 것이다.

 

 

 

 

 

 


3강 <코딩테스트, 기초, 배열 인터뷰 Binary Search>

일반적인 배열 Search는 time complexity가 O(n) 이 된다.

그러나, Binary Search를 사용하게 되면 time complexity가 O(logn) 이 된다.

 

 

 

이것도 left index와 right index가 사용된다. left index와 right index의 중간 지점과 검색하려는 숫자를 비교해 나가며, 탐색 범위를 좁혀 나가는 것이 특징이다. 

pivot = (L + R) / 2

 

 

만약 1 3 5 6 7 15 20 이라는 배열이 있을 때, 16이라는 숫자를 Search 하려고 한다.

(0번 인덱스 + 6번 인덱스) / 2 = 3번 인덱스(피벗)

 

3번 인덱스인 6이 pivot이 되면서 16과 6을 비교했을 때, 16이 더 크다 -> Left index는 7로 옮겨간다.

....과정을 반복해서

Left index와 right index 가 역전되면 return -1 (실패라는 뜻)을 해준다.

 

 

 

 

 

 

맨 첫줄 코드부터 설명하면, left index = 0 &  right index = nums.length로 지정해준다.

left index가 right index보다 항상 왼쪽에 있을 때에 이 반복문은 실행된다.

피벗을 구해주고

1) 만약 이 피벗이 목표 숫자와 같다면 피벗 리턴 -> 반복문 빠져나오기

2) 피벗 < 목표 숫자라면, left index는 피벗의 오른쪽으로 이동

3) 피벗 > 목표 숫자라면, right index는 피벗의 왼쪽으로 이동

-> 이 과정을 반복하여 언젠가 left index와 right index가 교차된다면 while 조건문에 위배되므로 실행이 종료된다. (찾고자 하는 숫자를 못찾은 Case 가 된다)  

 

 

 

 

 

 

 


4강 <코딩테스트, 초급, Movezeros>

[ 0 5 0 7 6 3 ] 이라는 배열이 있을 때, 0을 맨 뒤로 옮기면서 5 7 6 3 은 순서가 바뀌지 않는게 포인트이다.

-> [ 5 7 6 3 0 0 ]

 

 

몇가지 방법을 생각해 볼 수 있다.

1) 직관적으로 0을 찾아서 뒤로 보내기, 그리고 뒤에 있는 숫자를 한 칸씩 앞으로 이동

2) 0을 버블정렬을 이용해서 뒤로 한칸씩 점진적으로 보내기 = O(n * 0의 개수)

 

 

 

여기서 0이 아닌 숫자를 찾아서 왼쪽으로 보내는 방법을 생각해보자! (Zeromoves)

 

[ 0 5 0 7 6 3 ]

항상 0을 가리켜야 하는 파란색 화살표와 0 아닌 숫자를 가리켜야 하는 주황색 화살표로 생각(0번 인덱스부터 둘다 시작)

주황색 인덱스는 오른쪽 이동하여 5를 가르키게 되고 이때 파란색 인덱스와 swap이 발생한다.

그리고 파란색 인덱스는 오른쪽 한 칸 이동

(그 다음은 과정이 앞과 같다)

주황색 인덱스가 움직이고 7까지 한칸씩 이동 -> swap 발생 ......

 

 

 

wIdx는 파란색 인덱스, idx는 주황색 인덱스로 가정.

if 문에서 주황색 인덱스가 0 아닌 숫자를 가리킬 때, 파란색 인덱스와 swap 함수를 통해 교환한 다음 파란색 인덱스를 오른쪽으로 한 칸 이동해준다.

 

 

 

 

 

근데 여기서 두 인덱스 모두 0이 아닌 숫자를 가리킬 때 어떻게 될지 생각해보자.

 

 

 

그럴 땐 이렇게 코드를 작성해주면 된다. 주황색 인덱스와 파란색 인덱스가 copy의 개념으로 되며,

 

두 인덱스를 동시에 같이 한 칸씩 이동해주면 된다.

그 다음 뒤에 모두 0으로 복사한다.

 

 

 

문풀

(Inplace 알고리즘이란 추가적인 메모리 공간을 많이 필요로 하지 않는 혹은 전혀 필요하지 않는 알고리즘을 의미한다. 통상적으로, 공간은 O(logn)이고 O(n)이 될 때도 있다.

즉, n 길이의 리스트가 있고, 이 리스트를 정렬할 때 추가적으로 메모리 공간을 할당하지 않아도 정렬이 이뤄진다면 in-place 알고리즘이라고 불릴 수 있는 것이다.

 

In-place하지 않은 알고리즘은 n 길이의 리스트를 정렬할 때, n 만큼의 메모리보다 더 많은 메모리 공간을 할당한다. 즉, 이런 알고리즘들은 space complexity가 높다.)

 


5강 <코딩테스트, 초급, find pivot index>

[ 1 8 2 9 2 3 6 ] 이라는 배열이 있을 때, 9를 피벗으로 하고 피벗 기준 왼쪽 숫자의 합과 오른쪽 숫자의 합을 비교했을때 이 둘이 같으면 9가 피벗이 된다는 개념이다. 3번 인덱스를 리턴해주는 것이 정답이 된다.

[ 2 5 7 ] 일 경우, 피벗을 못 찾으므로 -1 을 리턴해주면 된다(실패)

 

이때 피벗을 앞에서부터 하나씩 잡게 되면 O(n) * n 가 된다. (n번 반복하게 되니까) - 좋지 않은 방법

 

 

( solution )

전체 sum을 구하면 O(n) 발생

1을 피벗으로 할때, 왼쪽은 0  &  오른쪽은 합 - 1 을 해준다.   ( O(1) 발생 )

8을 피벗으로 할때, 왼쪽은 0 + 1  &  오른쪽은 합 - 1 - 8 을 해준다.   ( O(1) 발생 )

....   O(1) * n 발생 

 

따라서 O(n) + O(n) => O(n) 이 된다.

 

 

 

 

accumulation 함수를 통해서 sum을 구해준다.

leftsum = 0 , rightSum = sum 으로 한다.

인덱스를 한 칸씩 이동하는 for문에서 rightSum에서는 num을 빼주고 이때 leftsum == rightsum 이면 인덱스를 리턴해준다. 인덱스가 한 칸 업데이트 되면 leftSum 에는 leftSum + 과거피벗넘버...

맨 마지막 pastPivotNum = num 을 써줌으로써, update 가 된다.

 

 

 

 

 

+ )

minimum size subarray sum

배열에서 합이 7인 최소 길이의 배열 찾기

이번 강의 문제를 Sliding 으로 하면 O(n)으로 해결이 가능하다. (직접 해보기 추천)

 

 

 

'🏃‍♀️ 코테 연습' 카테고리의 다른 글

27. N!의 표현법  (0) 2021.06.23
26. 말아톤  (0) 2021.06.19
25. 석차 구하기  (0) 2021.06.11
24. Jolly Jumpers  (0) 2021.06.10
23. 연속 부분 증가수열  (0) 2021.06.09