반응형

선택 정렬, 버블 정렬, 삽입 정렬의 한계

: O(N*N)은 데이터 갯수가 10만 개만 넘어가도 일반적인 상황에서 사용하기가 매우 어려운 알고리즘이다.

2^10 = 1,000

2^20 = 1,000,000

log(2)N = (N이 1,000,000일 때) 20

 

퀵 정렬(Quick Sort)

: 대표적인 분할 정복 알고리즘으로 특정한 값을 기준으로 큰 숫자와 작은 숫자를 서로 교환한 후 배열을 반으로 나누는 정렬 알고리즘

더보기

분할 정복

: 배열을 분할해서 계산하는 알고리즘

 

퀵 정렬(Quick Sort) Sequence

더보기

기준값 = 피벗(Pivot)

왼쪽에서 오른쪽으로 이동하면서 Pivot 보다 큰 값 하나 선택

오른 쪽에서 왼쪽으로 이동하면서 Pivot보다 작은 값 하나 선택

작은 값의 index < 큰 값의 index: Pivot과 작은 값 교환

작은 값의 index > 큰 값의 index: 작은 값과 큰 값 교환

 

 

Code

#include <iostream>
using namespace std;

int number = 10;
int Data[10] = {1, 10, 5, 8, 7, 6, 4, 3, 2, 9};

void quickSort_up(int *data, int start, int end){
    // start: 정렬을 수행하는 부분집합의 첫 번째 원소
    // end: 정렬을 수행하는 부분집합의 마지막 원소

    // 원소가 1개인 경우
    if(start >= end){
        return;
    }

    int key = start; // pivot

    int i = start + 1; // pivot 값에서 오른쪽으로 이동하면서 pivot값 보다 큰 값을 찾기 위해 존재하는 index
    int j = end; // 정렬을 수행하는 부분집합의 마지막 원소에서부터 왼쪽으로 이동하면서 pivot 값보다 작은 값을 찾기 위해 존재하는 index
    int tmp;

    // 엇갈리는 경우 while 탈출
    while(i <= j){
        // i번째 원소가 pivot 값 보다 작으면 i 오른쪽으로 이동(pivot 값보다 큰 값을 만날 때 까지 오른쪽으로 이동)
        while(data[i] <= data[key]){
            i++;
        }

        // j번째 원소가 pivot 값 보다 크면 j 왼쪽으로 이동(pivot 값보다 작은 값을 만날 때 까지 왼쪽으로 이동)
        // index가 엇갈렸을 때 작은 값과 pivot 값을 변경해주기 때문에 j는 배열을 벗어나지 못하도록 해주어야 함
        while(data[j] >= data[key] && j > start){
            j--;
        }

        // 엇갈린 경우 pivot값과 현재 data 변경
        if(i > j){
            tmp = data[j];
            data[j] = data[key];
            data[key] = tmp;
        }
        // 엇갈리지 않은 경우 i와 j index의 data 변경
        else{
            tmp = data[j];
            data[j] = data[i];
            data[i] = tmp;
        }
    }

    // 엇갈리는 경우 pivot 값이 정렬되었으므로, pivot 값을 재설정해주어야 함
    quickSort_up(data, start, j-1); // 왼쪽 data
    quickSort_up(data, j+1, end); // 오른쪽 data
}

void quickSort_down(int *data, int start, int end){
    // start: 정렬을 수행하는 부분집합의 첫 번째 원소
    // end: 정렬을 수행하는 부분집합의 마지막 원소

    // 원소가 1개인 경우
    if(start >= end){
        return;
    }

    int key = start; // pivot

    int i = start + 1; // pivot 값에서 오른쪽으로 이동하면서 pivot값 보다 큰 값을 찾기 위해 존재하는 index
    int j = end; // 정렬을 수행하는 부분집합의 마지막 원소에서부터 왼쪽으로 이동하면서 pivot 값보다 작은 값을 찾기 위해 존재하는 index
    int tmp;

    // 엇갈리는 경우 while 탈출
    while(i <= j){
        // i번째 원소가 pivot 값 보다 작으면 i 오른쪽으로 이동(pivot 값보다 큰 값을 만날 때 까지 오른쪽으로 이동)
        while(data[i] >= data[key]){
            i++;
        }

        // j번째 원소가 pivot 값 보다 크면 j 왼쪽으로 이동(pivot 값보다 작은 값을 만날 때 까지 왼쪽으로 이동)
        // index가 엇갈렸을 때 작은 값과 pivot 값을 변경해주기 때문에 j는 배열을 벗어나지 못하도록 해주어야 함
        while(data[j] <= data[key] && j > start){
            j--;
        }

        // 엇갈린 경우 pivot값과 현재 data 변경
        if(i > j){
            tmp = data[j];
            data[j] = data[key];
            data[key] = tmp;
        }
        // 엇갈리지 않은 경우 i와 j index의 data 변경
        else{
            tmp = data[j];
            data[j] = data[i];
            data[i] = tmp;
        }
    }

    // 엇갈리는 경우 pivot 값이 정렬되었으므로, pivot 값을 재설정해주어야 함
    quickSort_down(data, start, j-1); // 왼쪽 data
    quickSort_down(data, j+1, end); // 오른쪽 data
}

int main(void){
    quickSort_up(Data, 0, number-1); // 오름차순
    for(int i=0;i<10;i++){
        cout << Data[i] << " ";
    }
    cout << endl;
    quickSort_down(Data, 0, number-1); // 내림차순
    for(int i=0;i<10;i++){
        cout << Data[i] << " ";
    }
    return 0;
}

출력

1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1

 

만약 아래 배열을 정렬한다면?

선택 정렬의 시간 복잡도: N^2 = 100

퀵 정렬의 시간 복잡도: 

1 2 3 4 5 => 5 * 5 = 25

6 7 8 9 10 => 5 * 5 = 25

-> 25 + 25 = 50

∴ O(NlogN)의 시간복잡도를 갖는 알고리즘을 이용하면 100만개 정도의 데이터는 어렵지 않게 정렬이 가능하다.

 

시간복잡도

평균 : N*logN

최악의 경우: N^2

 

만약 이미 오름차순 정렬되어있는 배열을 퀵정렬을 이용해 오름차순 정렬한다면?

=> 분할 정복의 이점을 사용하지 못하고 있으므로, 이런 경우에는 insertion sort를 사용하는 게 효율적이다.

 

 

반응형
반응형

보물

티어 : Silver 4
시간 제한 : 2 초
메모리 제한 :128  MB
알고리즘 분류 : 수학, 그리디 알고리즘, 정렬

 

문제

옛날 옛적에 수학이 항상 큰 골칫거리였던 나라가 있었다. 이 나라의 국왕 김지민은 다음과 같은 문제를 내고 큰 상금을 걸었다.

길이가 N인 정수 배열 A와 B가 있다. 다음과 같이 함수 S를 정의하자.

S = A[0] × B[0] + ... + A[N-1] × B[N-1]

S의 값을 가장 작게 만들기 위해 A의 수를 재배열하자. 단, B에 있는 수는 재배열하면 안 된다.

S의 최솟값을 출력하는 프로그램을 작성하시오.

 

입력

첫째 줄에 N이 주어진다. 둘째 줄에는 A에 있는 N개의 수가 순서대로 주어지고, 셋째 줄에는 B에 있는 수가 순서대로 주어진다. N은 50보다 작거나 같은 자연수이고, A와 B의 각 원소는 100보다 작거나 같은 음이 아닌 정수이다.

 

출력

첫째 줄에 S의 최솟값을 출력한다.

 

예제 입출력


Algorithm

정렬
1. A 배열 오름차순 정렬
2. B 배열 내림차순 정렬
3. S = {A의 최솟값 * B의 최댓값}의 합

 

Code

N = int(input())
A = [int(num) for num in input().split()]
B = [int(num) for num in input().split()]

# A 배열 오름차순, B 배열 내림차순
A.sort()
B.sort(reverse=True)

# S = A최솟값 * B최댓값
S = 0
for idx in range(N):
    S += A[idx] * B[idx]
    
print(S)

메모리: 30840 KB
시간: 72 ms

반응형
반응형

숫자 카드 2

티어 : Silver 4
시간 제한 : 1 초
메모리 제한 : 256 MB
알고리즘 분류 : 자료 구조, 정렬, 이분 탐색

 

문제

숫자 카드는 정수 하나가 적혀져 있는 카드이다. 상근이는 숫자 카드 N개를 가지고 있다. 정수 M개가 주어졌을 때, 이 수가 적혀있는 숫자 카드를 상근이가 몇 개 가지고 있는지 구하는 프로그램을 작성하시오.

 

입력

첫째 줄에 상근이가 가지고 있는 숫자 카드의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 둘째 줄에는 숫자 카드에 적혀있는 정수가 주어진다. 숫자 카드에 적혀있는 수는 -10,000,000보다 크거나 같고, 10,000,000보다 작거나 같다.

셋째 줄에는 M(1 ≤ M ≤ 500,000)이 주어진다. 넷째 줄에는 상근이가 몇 개 가지고 있는 숫자 카드인지 구해야 할 M개의 정수가 주어지며, 이 수는 공백으로 구분되어져 있다. 이 수도 -10,000,000보다 크거나 같고, 10,000,000보다 작거나 같다.

 

출력

첫째 줄에 입력으로 주어진 M개의 수에 대해서, 각 수가 적힌 숫자 카드를 상근이가 몇 개 가지고 있는지를 공백으로 구분해 출력한다.

 

예제 입출력


Algorithm

1. 숫자 입력받을 때 Dictionary에 해당 숫자 개수 저장
2. M개 숫자에 대해 Dictionary의 value 출력

 

Code

# Dictionary 이용
N = int(input())
num_list = list(map(int, input().split()))
nums = {}
for num in num_list:
    if num not in nums:
        nums[num] = 1
    else:
        nums[num] += 1

M = int(input())
num_list = list(map(int, input().split()))
for num in num_list:
    if num in nums:
        print(nums[num], end = ' ')
    else:
        print(0, end = ' ')

메모리: 132176 KB
시간: 936 ms

 

# bisect 이용
import bisect

N = int(input())
num_list = list(map(int, input().split()))

# 오름차순 정렬
num_list.sort()

M = int(input())
lists = list(map(int, input().split()))

for num in lists:
    first = bisect.bisect_left(num_list, num)
    second = bisect.bisect_right(num_list, num)
    print(second-first, end = ' ')

메모리: 114300 KB

시간: 1696 ms

반응형

'백준 > Python' 카테고리의 다른 글

[백준 10950] A+B - 3 Python  (0) 2022.05.23
[백준 2558] A+B - 2 Python  (0) 2022.05.23
[백준 10866] 덱 Python  (0) 2022.05.12
[백준 5972] 택배 배송 Python  (0) 2022.05.12
[백준 1932] 정수 삼각형 Python  (0) 2022.05.09
반응형

로프

티어 : Silver 4
시간 제한 : 2 초
메모리 제한 : 192 MB
알고리즘 분류 : 수학, 그리디 알고리즘, 정렬

 

문제

N(1 ≤ N ≤ 100,000)개의 로프가 있다. 이 로프를 이용하여 이런 저런 물체를 들어올릴 수 있다. 각각의 로프는 그 굵기나 길이가 다르기 때문에 들 수 있는 물체의 중량이 서로 다를 수도 있다.

하지만 여러 개의 로프를 병렬로 연결하면 각각의 로프에 걸리는 중량을 나눌 수 있다. k개의 로프를 사용하여 중량이 w인 물체를 들어올릴 때, 각각의 로프에는 모두 고르게 w/k 만큼의 중량이 걸리게 된다.

각 로프들에 대한 정보가 주어졌을 때, 이 로프들을 이용하여 들어올릴 수 있는 물체의 최대 중량을 구해내는 프로그램을 작성하시오. 모든 로프를 사용해야 할 필요는 없으며, 임의로 몇 개의 로프를 골라서 사용해도 된다.

 

입력

첫째 줄에 정수 N이 주어진다. 다음 N개의 줄에는 각 로프가 버틸 수 있는 최대 중량이 주어진다. 이 값은 10,000을 넘지 않는 자연수이다.

 

출력

첫째 줄에 답을 출력한다.

 

예제 입출력


Algorithm

Greedy 이용
1. 각 로프의 중량을 리스트에 담아 sort
2. 1개 쓸 때부터 N개 쓸 때까지의 최댓값 구하기
    ☞ 각 최댓값은 [N-i] * i

 

Code

import sys
input = sys.stdin.readline

# 입력
N = int(input())
weights = []
for _ in range(N):
    weights.append(int(input()))

# 중량 리스트 오름차순 정렬
weights.sort()

# 로프 i개 쓸 때부터 N개 쓸 때까지 최댓값 갱신
max_weights = 0
for i in range(1, N+1):
    if max_weights < weights[N-i] * i:
        max_weights = weights[N-i] * i
print(max_weights)

메모리: 34080 KB
시간: 140 ms

반응형

'백준 > Python' 카테고리의 다른 글

[백준 10973] 이전 순열 Python  (0) 2022.04.08
[백준 2581] 소수 Python  (0) 2022.04.08
[백준 10972] 다음 순열 Python  (0) 2022.04.07
[백준 2577] 숫자의 개수 Python  (0) 2022.04.07
[백준 1931] 회의실 배정 Python  (0) 2022.04.07
반응형

회의실 배정

티어 : Silver 2
시간 제한 : 2 초
메모리 제한 : 128 MB
알고리즘 분류 : 그리디 알고리즘, 정렬

 

문제

한 개의 회의실이 있는데 이를 사용하고자 하는 N개의 회의에 대하여 회의실 사용표를 만들려고 한다. 각 회의 I에 대해 시작시간과 끝나는 시간이 주어져 있고, 각 회의가 겹치지 않게 하면서 회의실을 사용할 수 있는 회의의 최대 개수를 찾아보자. 단, 회의는 한번 시작하면 중간에 중단될 수 없으며 한 회의가 끝나는 것과 동시에 다음 회의가 시작될 수 있다. 회의의 시작시간과 끝나는 시간이 같을 수도 있다. 이 경우에는 시작하자마자 끝나는 것으로 생각하면 된다.

 

입력

첫째 줄에 회의의 수 N(1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N+1 줄까지 각 회의의 정보가 주어지는데 이것은 공백을 사이에 두고 회의의 시작시간과 끝나는 시간이 주어진다. 시작 시간과 끝나는 시간은

보다 작거나 같은 자연수 또는 0이다.

 

출력

첫째 줄에 최대 사용할 수 있는 회의의 최대 개수를 출력한다.

 

예제 입출력

 

힌트

(1,4), (5,7), (8,11), (12,14) 를 이용할 수 있다.


Algorithm

Greedy
1. 리스트로 입력받아 끝나는 시간을 기준으로 오름차순 정렬
2. stack에 첫 번째 회의 추가
3. stack의 마지막 회의의 끝나는 시간보다 시작 시간이 크거나 같은 회의만 추가
4. stack의 길이 출력

 

Code

import sys
input = sys.stdin.readline
    
# 입력
N = int(input())
I = []
for _ in range(N):
    I.append(tuple(map(int, input().split())))
    
# 시작 시간, 회의 시간 순서대로 기준을 잡아 정렬
I.sort(key = lambda x: (x[1], x[0]))

# 회의 시작 시간이 이전 회의 끝나는 시간보다 크거나 같으면 추가
stack = [I[0]]
for index in range(1, N):
    if I[index][0] >= stack[-1][1]:
        stack.append(I[index])
print(len(stack))

메모리: 51636 KB
시간: 4420 ms

반응형

'백준 > Python' 카테고리의 다른 글

[백준 10972] 다음 순열 Python  (0) 2022.04.07
[백준 2577] 숫자의 개수 Python  (0) 2022.04.07
[백준 2562] 최댓값 Python  (0) 2022.04.07
[백준 2529] 부등호 Python  (0) 2022.04.07
[백준 15661] 링크와 스타트 Python  (0) 2022.04.06
반응형

N번째 큰 수

티어 : Gold 5
시간 제한 : 1 초
메모리 제한 : 12 MB
알고리즘 분류 : 자료 구조, 정렬, 우선순위 큐

 

문제

N×N의 표에 수 N2개 채워져 있다. 채워진 수에는 한 가지 특징이 있는데, 모든 수는 자신의 한 칸 위에 있는 수보다 크다는 것이다. N=5일 때의 예를 보자.

이러한 표가 주어졌을 때, N번째 큰 수를 찾는 프로그램을 작성하시오. 표에 채워진 수는 모두 다르다.

 

입력

첫째 줄에 N(1 ≤ N ≤ 1,500)이 주어진다. 다음 N개의 줄에는 각 줄마다 N개의 수가 주어진다. 표에 적힌 수는 -10억보다 크거나 같고, 10억보다 작거나 같은 정수이다.

 

출력

첫째 줄에 N번째 큰 수를 출력한다.

 

예제 입출력


Algorithm

정렬
1. 입력받을 때마다 내림차순 정렬해 리스트에 N개 씩 저장
2. 입력을 모두 받았을 때는 리스트의 가장 마지막 값 출력

 

Code

import sys
input = sys.stdin.readline
N = int(input())
nums = []
for _ in range(N):
    nums += list(map(int, input().split()))
    nums.sort(reverse = True)
    nums = nums[:N]

print(nums[-1])

메모리: 30864 KB
시간: 844 ms

반응형

'백준 > Python' 카테고리의 다른 글

[백준 15649] N과 M (1) Python  (0) 2022.04.04
[백준 1748] 수 이어 쓰기 1 Python  (0) 2022.04.04
[백준 3190] 뱀 Python  (0) 2022.03.31
[백준 12904] A와 B Python  (0) 2022.03.31
[백준 14500] 테트로미노 Python  (0) 2022.03.31
반응형

일곱 난쟁이

티어 : Bronze 2
시간 제한 : 2 초
메모리 제한 : 128 MB
알고리즘 분류 : 브루트포스 알고리즘, 정렬

 

문제

왕비를 피해 일곱 난쟁이들과 함께 평화롭게 생활하고 있던 백설공주에게 위기가 찾아왔다. 일과를 마치고 돌아온 난쟁이가 일곱 명이 아닌 아홉 명이었던 것이다.

아홉 명의 난쟁이는 모두 자신이 "백설 공주와 일곱 난쟁이"의 주인공이라고 주장했다. 뛰어난 수학적 직관력을 가지고 있던 백설공주는, 다행스럽게도 일곱 난쟁이의 키의 합이 100이 됨을 기억해 냈다.

아홉 난쟁이의 키가 주어졌을 때, 백설공주를 도와 일곱 난쟁이를 찾는 프로그램을 작성하시오.

 

입력

아홉 개의 줄에 걸쳐 난쟁이들의 키가 주어진다. 주어지는 키는 100을 넘지 않는 자연수이며, 아홉 난쟁이의 키는 모두 다르며, 가능한 정답이 여러 가지인 경우에는 아무거나 출력한다.

 

출력

일곱 난쟁이의 키를 오름차순으로 출력한다. 일곱 난쟁이를 찾을 수 없는 경우는 없다.

 

예제 입출력


Algorithm

완전 탐색 이용
1. 난쟁이의 키를 리스트로 입력
2. 두 개씩 뺀 후 리스트의 합이 100이 되는지 확인

 

Code

import sys
input = sys.stdin.readline

heights = [0 for _ in range(9)]
for i in range(9):
    heights[i] = int(input())

# 리스트 오름차순
heights.sort()

# 리스트에서 두개씩 빼어 리스트의 합이 100이 되는지 확인
temp = []
for i in range(len(heights)):
    for j in range(i, len(heights)):
        if sum(heights[:i]+heights[i+1:j]+heights[j+1:]) == 100:
            temp += heights[:i] + heights[i+1:j] + heights[j+1:]
            break
    if len(temp) > 0:
        break
    
answer = ''
for i in temp:
    answer += str(i) + '\n'
print(answer)

메모리: 30860 KB
시간: 68 ms

반응형
반응형

먹을 것인가 먹힐 것인가

티어 : Silver 3
시간 제한 : 1 초
메모리 제한 : 256 MB
알고리즘 분류 : 

 

문제

심해에는 두 종류의 생명체 A와 B가 존재한다. A는 B를 먹는다. A는 자기보다 크기가 작은 먹이만 먹을 수 있다. 예를 들어, A의 크기가 {8, 1, 7, 3, 1}이고, B의 크기가 {3, 6, 1}인 경우에 A가 B를 먹을 수 있는 쌍의 개수는 7가지가 있다. 8-3, 8-6, 8-1, 7-3, 7-6, 7-1, 3-1.

두 생명체 A와 B의 크기가 주어졌을 때, A의 크기가 B보다 큰 쌍이 몇 개나 있는지 구하는 프로그램을 작성하시오.

 

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스의 첫째 줄에는 A의 수 N과 B의 수 M이 주어진다. 둘째 줄에는 A의 크기가 모두 주어지며, 셋째 줄에는 B의 크기가 모두 주어진다. 크기는 양의 정수이다. (1 ≤ N, M ≤ 20,000) 

 

출력

각 테스트 케이스마다, A가 B보다 큰 쌍의 개수를 출력한다.

 

예제 입출력


Algorithm

1. bisect_left 이용
2. bisect_left()의 x값을 본인으로 했을 때의 반환값이 현재 index의 값이 먹을 수 있는 먹이 수
3. 반환되는 값 누적 합해 출력

 

Code

import sys
from bisect import bisect_left

input = sys.stdin.readline

# 입력
T = int(input())
for _ in range(T):
    _, _ = map(int, input().split())
    A = list(map(int, input().split()))
    B = list(map(int, input().split()))
    
    # B 정렬
    B.sort()
    
    answer = 0
    for i in A:
        # B List에서 A의 보다 작은 원소의 개수 누적합
        answer += bisect_left(B, i)
    print(answer)

메모리: 353116 KB
시간: 172 ms

반응형

'백준 > Python' 카테고리의 다른 글

[백준 6236] 용돈 관리 Python  (0) 2022.03.09
[백준 1654] 랜선 자르기 Python  (0) 2022.03.08
[백준 2512] 예산 Python  (0) 2022.03.08
[백준 2776] 암기왕 Python  (1) 2022.03.08
[백준 1920] 수 찾기 Python  (0) 2022.03.08

+ Recent posts