๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐Ÿ’ปAlgorithm/์ด๋ก 

๋ถ„ํ• ์ •๋ณต(Divide and Conquer)

๋ถ„ํ• ์ •๋ณต

 

-์ฃผ์–ด์ง„ ๋ฌธ์ œ๋ฅผ ๋‘˜ ์ด์ƒ์˜ ๋ถ€๋ถ„ ๋ฌธ์ œ๋กœ ๋‚˜๋ˆ„์–ด์„œ ํ‘ธ๋Š” ๋ฐฉ๋ฒ•

-๋น„์Šทํ•œ ํฌ๊ธฐ๋กœ ๋ฌธ์ œ๋ฅผ ๋‚˜๋ˆ”

-์žฌ๊ท€ํ˜ธ์ถœ ์‚ฌ์šฉ

 

 

 

๋ถ„ํ• ์ •๋ณต ๊ณผ์ •

  1. Divide :๋ถ€๋ถ„ ๋ฌธ์ œ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ 2๊ฐœ ์ด์ƒ์˜ ๋ฌธ์ œ๋กœ ๋‚˜๋ˆˆ๋‹ค.
  2. Conquer : ๋” ์ด์ƒ ๋‚˜๋ˆŒ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ํ˜„์žฌ ๋ฌธ์ œ๋ฅผ ์ •๋ณตํ•œ๋‹ค.
  3. Combine : ํ•ด๊ฒฐ๋œ ๋ฌธ์ œ๋“ค์„ ๋ณ‘ํ•ฉํ•˜์—ฌ ๊ธฐ์กด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค.

 

 

๋ถ„ํ•  ํšŸ์ˆ˜

์ž…๋ ฅ์˜ ํฌ๊ธฐ๊ฐ€ n์ด๊ณ  ์ด ๋ถ„ํ• ํ•œ ํšŸ์ˆ˜๊ฐ€ k๋ผ๋ฉด.

-1๋ฒˆ ๋ถ„ํ•  ํ›„ ์ž…๋ ฅ ํฌ๊ธฐ : n/2

-2๋ฒˆ ๋ถ„ํ•  ํ›„ ์ž…๋ ฅ ํฌ๊ธฐ : n/2^2

...

-k๋ฒˆ ๋ถ„ํ•  ํ›„ ์ž…๋ ฅ ํฌ๊ธฐ : n/2^k

--> n/2^k ๊ฐ€ 1 ์ด๋ผ๋ฉด ๋” ์ด์ƒ ๋ถ„ํ•  ๋ถˆ๊ฐ€

 

๋ถ„ํ•  ํšŸ์ˆ˜

 

 

๋ถ„ํ• ์ •๋ณต์˜ ์‚ฌ์šฉ

1. ํ•ฉ๋ณ‘์ •๋ ฌ(Merge Sort)

์ž…๋ ฅ์ด 2๊ฐœ์˜ ๋ถ€๋ถ„๋ฌธ์ œ๋กœ ํฌ๊ธฐ๊ฐ€ ๋ฐ˜์”ฉ ์ค„์–ด๋“œ๋Š” ๋ถ„ํ•  ์ •๋ณต ์•Œ๊ณ ๋ฆฌ์ฆ˜

-n๊ฐœ์˜ ์ˆซ์ž๋“ค์„ n/2๊ฐœ์”ฉ 2๊ฐœ์˜ ๋ถ€๋ถ„๋ฌธ์ œ๋กœ ๋ถ„ํ• 

-2๊ฐœ์˜ ์ •๋ ฌ๋œ ๋ถ€๋ถ„์„ ํ•ฉ๋ณ‘ํ•˜์—ฌ ์ •๋ ฌ(์ •๋ณต)

 

์‹œ๊ฐ„๋ณต์žก๋„ : O(nlogn) 

 ๊ฐ ์ธต(๋ถ„ํ• )์—์„œ ๋น„๊ต ๊ณ„์‚ฐ ํšŸ์ˆ˜ = O(n)

 ์ธต ์ˆ˜=๋ถ„ํ•  ํšŸ์ˆ˜=log2n

 ์‹œ๊ฐ„๋ณต์žก๋„=> log2n*O(n)=O(nlogn)

 

์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌํ˜„(python)

import random
size=15
num=[]
result=[0]*size
#๋žœ๋ค์œผ๋กœ ์ˆซ์ž ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ํ•จ์ˆ˜
def makeList(num):
    for i in range(size):
      num.append(int(random.random()*100+1))
      #1๋ถ€ํ„ฐ 100๊นŒ์ง€์˜ ์ˆ˜ ์ค‘ ํ•˜๋‚˜

def merge(num,result,left,mid,right):
    i=left;j=mid+1;k=left
    #ํ•ฉ๋ณ‘
    while(i<=mid and j<=right):
        if(num[i]<=num[j]):
            result[k]=num[i]
            k+=1
            i+=1
        else:
            result[k]=num[j]
            k+=1
            j+=1
    if(i>mid):
        for a in range(j,right+1):
            result[k]=num[a]
            k+=1
    else:
        for a in range(i,mid+1):
            result[k]=num[a]
            k+=1
    for a in range(left,right+1):
        num[a]=result[a]
    print(num,result)
    ##ํ•ฉ๋ณ‘ ํ›„ ๋‹ค์‹œ ๋Œ€์ž…


def mergeSort(num,result,left,right):
    if(left<right):
        mid=(left+right)//2
        mergeSort(num,result,left,mid)
        mergeSort(num,result,mid+1,right)
        merge(num,result,left,mid,right)

makeList(num)
print(*num)
mergeSort(num,result,0,size-1)
print(*result)

 

 

2. ํ€ต์ •๋ ฌ

์‚ฌ์‹ค ์ •๋ณต ํ›„ ๋ถ„ํ• ํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ๊ฐ ๋ถ€๋ถ„ ๋ฌธ์ œ์˜ ํฌ๊ธฐ๊ฐ€ ์ผ์ •ํ•˜์ง€ ์•Š์€ ํ˜•ํƒœ์˜ ๋ถ„ํ• ์ •๋ณต ์•Œ๊ณ ๋ฆฌ์ฆ˜

-pivot์„ ์„ค์ •ํ•˜์—ฌ pivot๋ณด๋‹ค ์ž‘์€ ์›์†Œ๋Š” ์™ผ์ชฝ์œผ๋กœ ํฐ ์›์†Œ๋Š” ์˜ค๋ฅธ์ชฝ์œผ๋กœ ๋ถ„ํ• ํ•˜๊ณ  ์ค‘๊ฐ„์— pivot์„ ๋†“๋Š”๋‹ค.

-๋ถ„ํ• ๋œ ๋ถ€๋ถ„ ๋ฌธ์ œ๋“ค์— ๋Œ€ํ•ด์„œ๋„ ์ƒˆ๋กœ์šด pivot์„ ์„ค์ •ํ•˜์—ฌ ์œ„์™€ ๋™์ผํ•œ ๊ณผ์ •์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

 

์‹œ๊ฐ„๋ณต์žก๋„

pivot์œผ๋กœ ์–ด๋Š ๊ฒƒ์„ ์„ ํƒํ•˜๋Š”์ง€์— ๋”ฐ๋ผ ์„ฑ๋Šฅ์ด ์ขŒ์šฐ๋œ๋‹ค.

-์ตœ์•…์˜ ๊ฒฝ์šฐ(๊ฐ€์žฅ ์ž‘์€/ํฐ ์›์†Œ๊ฐ€ pivot์ธ ๊ฒฝ์šฐ): (n-1)+(n-2)+...+1=> O(n^2)

-์ตœ์„ ์˜ ๊ฒฝ์šฐ(์ค‘๊ฐ„ ํฌ๊ธฐ์˜ ์›์†Œ๊ฐ€ pivot์ธ ๊ฒฝ์šฐ): ์ธต์ˆ˜ * O(n) = logn*O(n) = O(nlogn)

-ํ‰๊ท ์˜ ๊ฒฝ์šฐ(ํ•ญ์ƒ ๋žœ๋คํ•˜๊ฒŒ ์„ ํƒํ•˜๋Š” ๊ฒฝ์šฐ): O(nlogn)

 

์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌํ˜„(python)

import random
size=15
num=[]
result=[0]*size
#๋žœ๋ค์œผ๋กœ ์ˆซ์ž ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ํ•จ์ˆ˜
def makeList(num):
    for i in range(size):
      num.append(int(random.random()*100+1))
      #1๋ถ€ํ„ฐ 100๊นŒ์ง€์˜ ์ˆ˜ ์ค‘ ํ•˜๋‚˜

def partition(num,left,right):
    pivot=num[left] #pivot์„ ๋žœ๋ค์œผ๋กœ ์„ค์ •ํ•ด๋„ ๋จ
    low=left; high=right

    while(low<high):
        while(num[low]<=pivot and low<right):
            low+=1
        while(num[high]>=pivot and high>left):
            high-=1
        if low<high:
            ##low์œ„์น˜์˜ ์›์†Œ๋Š” pivot๋ณด๋‹ค ํฌ๊ณ  high์œ„์น˜์˜ ์›์†Œ๋Š” pivot๋ณด๋‹ค ์ž‘์œผ๋ฏ€๋กœ swap
            num[low],num[high]=num[high],num[low]
        
    num[left],num[high]=num[high],num[left] #pivot์œ„์น˜ ๊ณ 
    ##pivot์˜ ์œ„์น˜ return
    return high 

def quickSort(num,left,right):
    if(left<right):
        q=partition(num,left,right)
        quickSort(num,left,q-1)
        quickSort(num,q+1,right)
        #pivot์„ ๊ธฐ์ค€์œผ๋กœ ๋‘ ๊ทธ๋ฃน์œผ๋กœ ๋ถ„ํ• 

makeList(num)
print(*num)
quickSort(num,0,size-1)
print(*num)

 

 

3.์ด์ง„ํƒ์ƒ‰(์ด๋ถ„ํƒ์ƒ‰)

ํƒ์ƒ‰ ๋ฒ”์œ„๋ฅผ ๋‘ ๋ถ€๋ถ„์œผ๋กœ ๋‚˜๋ˆ ๊ฐ€๋ฉด์„œ ์›ํ•˜๋Š” ์›์†Œ๋ฅผ ์ฐพ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ํƒ์ƒ‰ ์ „ ์›์†Œ๊ฐ€ ์ •๋ ฌ๋˜์–ด ์žˆ์–ด์•ผํ•œ๋‹ค.

-ํƒ์ƒ‰ ๋ฒ”์œ„ ์„ค์ • ex)[s,e]

-ํƒ์ƒ‰ ์ง€์ (mid) ์„ค์ • ํ›„ ์ฐพ๋Š” ๊ฐ’๊ณผ ๋น„๊ต ex)mid=(s+e)//2

-mid๊ฐ€ ๋” ํฌ๋ฉด [s,mid-1]์—์„œ ๋‹ค์‹œ ํƒ์ƒ‰, ๋” ์ž‘์œผ๋ฉด [mid+1,e]์—์„œ ๋‹ค์‹œ ํƒ์ƒ‰

-s>e์ผ ๋•Œ ๊นŒ์ง€ ์œ„์˜ ๊ณผ์ • ๋ฐ˜๋ณต

 

์‹œ๊ฐ„๋ณต์žก๋„ : O(logn)

 

์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌํ˜„(python)

import random
size=15
num=[]
result=[0]*size
#๋žœ๋ค์œผ๋กœ ์ˆซ์ž ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ํ•จ์ˆ˜
def makeList(num):
    while True:
        temp=random.randint(1,20)
        #1๋ถ€ํ„ฐ 20์‚ฌ์ด์˜ ์ˆซ์ž
        if temp not in num:
            num.append(temp)
        if len(num)==size:
            break

def binary_search(target,num):
    start=0
    end=size-1
    while(start<=end):
        mid=(start+end)//2
        if num[mid]==target:
            return mid
        elif num[mid]>target:
            end=mid-1
        else:
            start=mid+1
    return None ##์ฐพ๊ณ ์ž ํ•˜๋Š” ์ˆ˜๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ


target=random.randint(1,20) #์ฐพ๊ณ ์žํ•˜๋Š” ์ˆ˜
makeList(num)
num.sort()
print(target)
print(num)
print(binary_search(target,num),"๋ฒˆ์งธ ์›์†Œ")

 

 

4.์„ ํƒ๋ฌธ์ œ

n๊ฐœ์˜ ์ˆซ์ž๋“ค ์ค‘์—์„œ k๋ฒˆ์งธ๋กœ ์ž‘์€ ์ˆซ์ž๋ฅผ ์ฐพ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.

k๋ฒˆ์งธ๋กœ ์ž‘์€ ์ˆซ์ž๋ฅผ ์ฐพ๋Š” ๋ฐฉ๋ฒ•์€

-์ตœ์†Œ ์ˆซ์ž๋ฅผ k๋ฒˆ ์ฐพ๋Š” ๋ฐฉ๋ฒ• (O(kn))

-์ˆซ์ž๋ฅผ ์ •๋ ฌํ•œ ํ›„, k๋ฒˆ์งธ ์ˆซ์ž๋ฅผ ์ฐพ๋Š” ๋ฐฉ๋ฒ• (O(nlogn))

-๋‘ ๊ทธ๋ฃน์œผ๋กœ ๋‚˜๋ˆ ์„œ ๋‘ ๊ทธ๋ฃน ์ค‘ ์–ด๋Š ๊ทธ๋ฃน์— ์†ํ•˜๋Š”์ง€ ์ฐพ์•„๊ฐ€๋Š” ๋ฐฉ๋ฒ•

   ->์™ผ์ชฝ ๊ทธ๋ฃน (k๋ฒˆ์งธ ์ž‘์€ ์ˆซ์ž) 

   ->์˜ค๋ฅธ์ชฝ ๊ทธ๋ฃน(k-์™ผ์ชฝ๊ทธ๋ฃน ํฌ๊ธฐ-1(pivot) ๋ฒˆ์งธ๋กœ ์ž‘์€ ์ˆซ์ž)

 

์‹œ๊ฐ„๋ณต์žก๋„

์ž…๋ ฅ ํฌ๊ธฐ๊ฐ€ n์—์„œ๋ถ€ํ„ฐ ํ‰๊ท ์ ์œผ๋กœ 3/4๋ฐฐ๋กœ ๊ฐ์†Œ, ํฌ๊ธฐ๊ฐ€ 1์ผ ๊ฒฝ์šฐ ๋ถ„ํ•  ์™„๋ฃŒ

n+3/4n+(3/4)^2n+...(3/4)^in = n[1+3/4+(3/4)^2+...+(3/4)^i] <= 2n

ํ‰๊ท  2ํšŒ์— ์ข‹์€ ๋ถ„ํ• ์ด ๋˜๋ฏ€๋กœ 2*O(n) = O(n)

 

์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌํ˜„(python)

import random
import sys
sys.setrecursionlimit(10**6)
size=15
num=[]

#๋žœ๋ค์œผ๋กœ ์ˆซ์ž ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ํ•จ์ˆ˜
def makeList(num):
    for i in range(size):
      num.append(int(random.random()*100+1))
      #1๋ถ€ํ„ฐ 100๊นŒ์ง€์˜ ์ˆ˜ ์ค‘ ํ•˜๋‚˜
      
def partition(num,left,right):
    pivot=num[left] #pivot์„ ๋žœ๋ค์œผ๋กœ ์„ค์ •ํ•ด๋„ ๋จ
    low=left; high=right

    while(low<high):
        while(num[low]<=pivot and low<right):
            low+=1
        while(num[high]>=pivot and high>left):
            high-=1
        if low<high:
            ##low์œ„์น˜์˜ ์›์†Œ๋Š” pivot๋ณด๋‹ค ํฌ๊ณ  high์œ„์น˜์˜ ์›์†Œ๋Š” pivot๋ณด๋‹ค ์ž‘์œผ๋ฏ€๋กœ swap
            num[low],num[high]=num[high],num[low]
        
    num[left],num[high]=num[high],num[left] #pivot์œ„์น˜ ๊ณ 
    ##pivot์˜ ์œ„์น˜ return
    return high

def selection(num,left,right,k):
    p=partition(num,left,right)
    s=p-left #์™ผ์ชฝ ๊ทธ๋ฃน์˜ ํฌ๊ธฐ
    if k<=s:
        return selection(num,left,p-1,k)
    elif k==s+1:
         return num[p]
    else:
        return selection(num,p+1,right,k-s-1)


makeList(num)
print(*num)
k=int(input())
print(selection(num,0,size-1,k))

 

 

์ถœ์ฒ˜ : ์•Œ๊ธฐ ์‰ฌ์šด ์•Œ๊ณ ๋ฆฌ์ฆ˜(๊ฐœ์ •ํŒ), ์–‘์„ฑ๋ด‰, ์ƒ๋Šฅ ์ถœํŒ์‚ฌ