본문 바로가기

Algorithm/Practice

프로그래머스 - 기능개발 (Python)

문제 설명

먼저 배포되어야 하는 순서대로 작업의 진도가 적힌 정수 배열 progresses와 각 작업의 개발 속도가 적힌 정수 배열 speeds가 주어질 때 각 배포마다 몇 개의 기능이 배포되는지를 return 하도록 solution 함수를 완성하세요.

programmers.co.kr/learn/courses/30/lessons/42586

 

코딩테스트 연습 - 기능개발

프로그래머스 팀에서는 기능 개선 작업을 수행 중입니다. 각 기능은 진도가 100%일 때 서비스에 반영할 수 있습니다. 또, 각 기능의 개발속도는 모두 다르기 때문에 뒤에 있는 기능이 앞에 있는

programmers.co.kr


# 풀이 1 : deque

def solution(progresses, speeds):
    from collections import deque
    import math
    queue = deque(progresses)
    spq = deque(speeds)
    days = []
    
    # 각 기능이 필요한 일수 배열 days 구하는 과정
    while(True):
        now = queue.popleft()
        now_sp = spq.popleft()
        day = math.ceil((100 - now) / now_sp)
        days.append(day)
        if len(queue) == 0:
            break
    
    
    answer = []
    days = deque(days)
    
    
    import copy
    while(True):
        
        temp = 1
        
        now = days.popleft()
        for day in copy.deepcopy(days):
            if now >= day:
                temp = temp + 1
                days.popleft()
                # now >= next 이면, 
                # now 일 만큼 기다렸다가 배포해야 하므로 
                # 배포 기능 개수 +1
                # 제거 pop
            else:
                break
        
        answer.append(temp)
        if len(days) == 0:
            break
    
    return answer


 

# Python 올림, 내림, 반올림 함수

import math

올림 >> math.ceil(i) 

내림 >> math.floor(i)

버림 >> math.trunc(i)

 


 

# RuntimeError: deque mutated during iteration.

아래 코드를 실행하면 오류가 발생한다.

for day in days:
            if now >= day:
                temp = temp + 1
                days.popleft()

원인 : for q in queue 반복문을 돌릴 때 deque의 내용 변질 or 사이즈 변경

해결방법 : list = days[:] 처럼 리스트 생성 or deepcopy 이용

 

+ 아래 코드를 실행할때, 반복문 과정에서 days와 dcopy_days 의 상태

def solution(progresses, speeds):
    from collections import deque
    import math
    queue = deque(progresses)
    spq = deque(speeds)
    days = []
    
    # 각 기능이 필요한 일수 배열 days 구하는 과정
    while(True):
        now = queue.popleft()
        now_sp = spq.popleft()
        day = math.ceil((100 - now) / now_sp)
        days.append(day)
        if len(queue) == 0:
            break
    
    
    answer = []
    days = deque(days)
    
    
    import copy
    while(True):
        print("= while문 분기 >>")
        print("id(days), days >> ", id(days), days)
        temp = 1
        now = days.popleft() 
        dcopy_days = copy.deepcopy(days)
        for day in dcopy_days:
            print("= for문 분기 >>")
            print("id(days), days >> ", id(days), days)
            print("id(dcopy_days), dcopy_days >> ", id(dcopy_days), dcopy_days)
            if now >= day:
                temp = temp + 1
                days.popleft()
                
            else:
                break
        
        answer.append(temp)
        if len(days) == 0:
            break
    
    return answer

 


 

# 얕은 복사 vs 깊은 복사

(.wikidocs.net/16038)

1. mutable과 immutable 객체

객체에는 mutable(변경 가능)과 immutable 객체가 있습니다.

(1) list 는 mutable 입니다.

  • a의 첫번째 원소를 변경한 후에도 id값은 변경없이 a의 변수가 변경되었습니다.
>>> a = [1, 2, 3]
>>> id(a)
4393788808
>>> a[0] = 5
>>> a
[5, 2, 3]
>>> id(a)
4393788808

(2) set도 mutable입니다.

  • |= set에서 or 연산입니다. 합집합이 됩니다.
  • 값은 변경되었으나 id는 변함없습니다.
>>> x = {1, 2, 3}
>>> x
{1, 2, 3}
>>> id(x)
4396095304
>>> x|={4,5,6}
>>> x
{1, 2, 3, 4, 5, 6}
>>> id(x)
4396095304

str은 immutable 입니다.

  • s 변수에 첫번째 글자를 변경 시도하면 에러가 발생합니다.
  • s에 다른 값을 할당하면, id가 변경됩니다. 재할당은 애초에 변수를 다시할당하는 것이므로 mutable과 immutable과는 다른 문제입니다. list또한 값을 재할당하면 id가 변경됩니다.
>>> s= "abc"
>>> s
'abc'
>>> id(s)
4387454680
>>> s[0]
'a'
>>> s[0] = 's'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s = 'def'
>>> s
'def'
>>> id(s)
4388970768

 

2. 변수 간 대입

(1) mutable한 객체의 변수 간 대입

  • list의 얕은 복사를 확인 해봅니다.
  • b 에 a를 할당하면 값이 할당되는 것이 아니라 같은 메모리 주소를 바라봅니다.
  • b를 변경하면 같이 a도 바뀝니다.
  • mutable한 다른 객체 또한 똑같은 현상이 나타납니다.
>>> a = [1, 2, 3]
>>> b = a # shallow copy
>>> b[0]= 5
>>> a
[5, 2, 3]
>>> b
[5, 2, 3]
>>> id(a)
4396179528
>>> id(b)
4396179528

(2) immutable한 객체의 변수간 대입

  • str 문자열의 얕은 복사를 확인해봅니다.
  • list와 똑같이 b를 a에 할당하면 같은 메모리 주소를 바라보게 됩니다.
  • 하지만 b에 다른 값을 할당하면 재할당이 이루어지며 메모리 주소가 변경됩니다.
  • 고로 a와 b는 다른 값을 가집니다.
>>> a = "abc"
>>> b = a
>>> a
'abc'
>>> b
'abc'
>>> id(a)
4387454680
>>> id(b)
4387454680
>>> b = "abcd"
>>> a
'abc'
>>> b
'abcd'
>>> id(a)
4387454680
>>> id(b)
4396456400

 

3. 얕은 복사(shallow copy)

  • list의 슬라이싱을 통한 새로운 값을 할당해봅니다.
  • 아래의 결과와 같이 슬라이싱을 통해서 값을 할당하면 새로운 id가 부여되며, 서로 영향을 받지 않습니다.
>>> a = [1,2,3]
>>> b = a[:]
>>> id(a)
4396179528
>>> id(b)
4393788808
>>> a == b
True
>>> a is b
False
>>> b[0] = 5
>>> a
[1, 2, 3]
>>> b
[5, 2, 3]
  • 하지만, 이러한 슬라이싱 또한 얕은 복사에 해당합니다.
  • 리스트안에 리스트 mutable객체 안에 mutable객체인 경우 문제가 됩니다.
  • id(a) 값과 id(b) 값은 다르게 되었지만, 그 내부의 객체 id(a[0])과 id(b[0])은 같은 주소를 바라보고 있습니다.
>>> a = [[1,2], [3,4]]
>>> b = a[:]
>>> id(a)
4395624328
>>> id(b)
4396179592
>>> id(a[0])
4396116040
>>> id(b[0])
4396116040
  • 재할당하는 경우는 문제가 없습니다. 메모리 주소도 변경되었습니다.
>>> a[0] = [8,9]
>>> a
[[8, 9], [3, 4]]
>>> b
[[1, 2], [3, 4]]
>>> id(a[0])
4393788808
>>> id(b[0])
4396116040
  • 하지만, a[1] 에 값을 변경하면 b[1]도 따라 변경됩니다.
>>> a[1].append(5)
>>> a
[[8, 9], [3, 4, 5]]
>>> b
[[1, 2], [3, 4, 5]]
>>> id(a[1])
4396389896
>>> id(b[1])
4396389896
  • copy 모듈의 copy 메소드 또한 얕은 복사입니다.
>>> import copy
>>> a = [[1,2],[3,4]]
>>> b = copy.copy(a)
>>> a[1].append(5)
>>> a
[[1, 2], [3, 4, 5]]
>>> b
[[1, 2], [3, 4, 5]]

 

4. 깊은 복사(deep copy)

  • 깊은 복사는 내부에 객체들까지 모두 새롭게 copy 되는 것입니다.
  • copy.deepcopy메소드가 해결해줍니다.
>>> import copy
>>> a = [[1,2],[3,4]]
>>> b = copy.deepcopy(a)
>>> a[1].append(5)
>>> a
[[1, 2], [3, 4, 5]]
>>> b
[[1, 2], [3, 4]]

 


 

+ 기타 파이썬 팁들이 있는 블로그 발견쓰 나중에 봐야지~

blog.naver.com/pjt3591oo/221767770567

 

[python] Python Level Up Guide - Part 1

1. 내장함수 사용​파이썬은 다양한 내장함수를 제공하고 있습니다. 내장함수 사용을 권장하는 이유는 C언...

blog.naver.com