Sad Puppy 3 '스택' 태그의 글 목록 :: 개발자 아지트

https://school.programmers.co.kr/learn/courses/3-/lessons/42584

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

문제설명

초 단위로 기록된 주식가격이 담긴 배열 prices가 매개변수로 주어질 때, 가격이 떨어지지 않은 기간은 몇 초인지를 return 하도록 solution 함수를 완성하세요.

 

제한사항

prices의 각 가격은 1 이상 10,000 이하인 자연수입니다.

prices의 길이는 2 이상 100,000 이하입니다.

 

입출력 예

prices    return

[1, 2, 3, 2, 3]      [4, 3, 1, 1, 0]

 

입출력 예 설명

1초 시점의 ₩1은 끝까지 가격이 떨어지지 않았습니다.

2초 시점의 ₩2은 끝까지 가격이 떨어지지 않았습니다.

3초 시점의 ₩3 1초뒤에 가격이 떨어집니다. 따라서 1초간 가격이 떨어지지 않은 것으로 봅니다.

4초 시점의 ₩2 1초간 가격이 떨어지지 않았습니다.

5초 시점의 ₩3 0초간 가격이 떨어지지 않았습니다.

문제 해결 방법

아 이문제는 참 어렵다! 시간 복잡도는 O(N^2)에 맞추면 안되고 O(NlogN)까지 가능하다. 

그런데 이 문제 아무리생각해봐도 O(NlogN)로 풀기 어려웠다. 그래서 O(N^2)로 풀어봤는데,,, 끝이 안난다. 

이조건 맞추면 저 조건 안맞고, 저 조건 맞추면 이 조건 안맞고 그랬다. 

 

그래서 결국 답을 보고 이해했다. 

 

이 문제는 효율성을 해결하기 위해서는 반드시 스택으로 풀어야한다. 그런데 이 문제 스택을 어디에 적용할지 떠올리기가 참 어렵다. 

 

코드 주석으로 설명하였다. 

 

코드 구현

 

기존 코드 - 미해결

def solution(prices):
    #O(N)으로 구현
    answer = []
    
    prices=list(prices)
    stackk=[]
    newPrices=[]
    newPrices = list(prices)

    for i in range(len(prices)):
        
        if i == 0:
            stackk.append(prices[i])
        else:
            
            newPrices.reverse()
            if len(newPrices)==0:
                break
            
            newPrices.pop()
            newPrices.reverse()
            cnt=0

            #print('prices[i]', prices[i-1], 'newPrices', newPrices)
            for price in newPrices:
                #print('price', price)
                if prices[i-1]<=price:
                     cnt+=1
            
            answer.append(cnt)
            
    answer.append(0)  
    #print(answer)
    
    
    
    return answer

 

개선 코드 - 해결

 

def solution(prices):
    answer = []
    total = len(prices)
    answer = [0] * total
    #각 초 시점의 길이를 넣을 배열
    stackk = [0] 

    # 스택을 0으로 초기화 한 이유는 순회를 인덱스 1부터 하기 위해서임 
    # prices의 0번 인덱스는 스택에 넣고 시작한다. 
    
    for i in range(1, total):
        # 1부터 total까지 순회한다. 
        # 0번 인덱스부터 total 인덱스까지 순회할 때, 가격의 증가만 있다면,
        # 계속 stackk에 넣는다. 
        # 만약 가격이 떨어진다면 그때부터는 스택에서 꺼내어서 하락한 가격의 인덱스로부터 길이를 구한다. 
        while stackk and prices[stackk[-1]]>prices[i]:
            a=stackk.pop()
            answer[a]=i-a
        stackk.append(i)
        
    while stackk: # 스택이 빌 때까지 순회하여 길이를 찾아준다. 
    #이 스택은 최종적으로 증가한 값들만 남아있다. 
        a=stackk.pop()
        answer[a]=total-a-1
        
    #print(answer)
    
    return answer

 

시간/공간 복잡도

O(NlogN)

최적화 및 개선

많은 개선을 했다. 음 로직을 아예 뜯어고침 

어려웠던 점/느낀점

답지를 안보고 혼자 코드 로직을 생각할 수 있을때 까지 연습하는것 까지 했다. 

다음에 또 풀때는 잘 풀었으면 좋겠다. 

https://school.programmers.co.kr/learn/courses/30/lessons/12906

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

문제설명

배열 arr가 주어집니다. 배열 arr의 각 원소는 숫자 0부터 9까지로 이루어져 있습니다. 이때, 배열 arr에서 연속적으로 나타나는 숫자는 하나만 남기고 전부 제거하려고 합니다. , 제거된 후 남은 수들을 반환할 때는 배열 arr의 원소들의 순서를 유지해야 합니다. 예를 들면,

 

  • arr = [1, 1, 3, 3, 0, 1, 1] 이면 [1, 3, 0, 1] 을 return 합니다.
  • arr = [4, 4, 4, 3, 3] 이면 [4, 3] 을 return 합니다.


배열 arr에서 연속적으로 나타나는 숫자는 제거하고 남은 수들을 return 하는 solution 함수를 완성해 주세요.

 

제한사항

배열 arr의 크기 : 1,000,000 이하의 자연수

배열 arr의 원소의 크기 : 0보다 크거나 같고 9보다 작거나 같은 정수

입출력 예

arr       answer

[1,1,3,3,0,1,1]      [1,3,0,1]

[4,4,4,3,3]          [4,3]

입출력 예 설명

입출력 예 #1,2

문제의 예시와 같습니다.

문제 해결 방법

stack을 이용하여 문제를 푼다. 
1. stack 구실을 할 임의의 리스트를 하나 만든다. 

2. arr의 원소를 순회하면서 임의의 리스트에 첫번째 원소를 push한다. 

2-1. 첫번째 이후의 원소들은 임의의 리스트의 마지막에 push한 값을 pop을 통해 꺼낸다.

2-2. 2-1번을 통해 꺼낸 값과 현재 넣고자 하는 arr의 원소를 비교하여 값이 같으면 pass하고 같지 않으면 push 한다. 

코드 구현

 

1. 효율성 통과하지 못한 코드 

def solution(arr):
    answer = []
    
    # pivot 변수 = p
    # 이전 pivot을 기억하는 변수 = pre_p
    check = 0
    pre_p = arr[0]
    l=len(arr)
    for i in range(1, len(arr)):
        p = arr[i]
        #print('p', p, 'pre_p', pre_p)
        if pre_p == p:
            pre_p = p
            arr[i] = 10
            # '-'를 세는 변수 = check
            check+=1
        else:
            pre_p=p
    
    for i in range(check):
        arr.remove(10)
        
    answer = arr
    return answer

 

 

2. 효율성 통과한 코드

def solution(arr):
    stack = []
    
    for i in range(len(arr)):
        if i == 0:
            stack.append((arr[i]))
        else:
            top = stack.pop()
            stack.append(top)
            if arr[i]==top:
                pass
            else:
                stack.append(arr[i])
    
    return stack

 

시간/공간 복잡도

1. 효율성을 통과하지 못한 코드: O(N^2)

2. 효율성을 통과한 코드: O(N)  

최적화 및 개선

처음에 효율성을 통과하지 못한 코드에 대해서 중첩 되지 않는 for문을 썼는데 왜 시간복잡도 효율성이 통과되지 않는지 이해가 안갔다. 혹시 내가 stack자료구조를 고려하지 않고 코드를 작성해서 그 부분에서 오류가 나는건가? 싶었다. 그래서 코드를 stack자료구조를 고려해서 리스트를 stack화 해서 코드를 짰다. 확실히 pop함수를 사용해서 그런가 편리하고 뒷처리를 해주지 않아도 되는 점이 깔끔하고 좋았다. 그리고 효율성에도 통과했다. 

 

그렇다면 1번 코드는 어디에서 효율성을 많이 잡아먹는가?

 

바로 for문에 있는 remove함수 때문이다. 

remove함수는 시간복잡도 O(N)을 잡아먹는다. 그런데 이걸 for문으로 처리하고있으니 시간복잡도가 O(N^2)이 되었던 것이였다. 

어려웠던 점

파이썬 각각의 함수들의 특성에 대해서는 잘 몰랐는데, 이렇게 문제를 풀면서 기억에 각인도 시키고 하니 좋다. 

어쩜 코딩테스트 문제들은 하나같이 문제 푸는 사람이 그 문제를 풀기위해서 알아야 하는것을 모른다면, 그것에 대해서 스스로 알게되지 않고서야 절대 문제를 못풀게끔 되어있는게 너무 신기하다. 이제야 드는 생각인데, 코딩테스트나 알고리즘 공부 어쩌면 좋은 제도일지도 모르겠다는 생각이 든다.  

문제설명

괄호가 바르게 짝지어졌다는 것은 '(' 문자로 열렸으면 반드시 짝지어서 ')' 문자로 닫혀야 한다는 뜻입니다. 예를 들어

 

"()()" 또는 "(())()" 는 올바른 괄호입니다.

")()(" 또는 "(()(" 는 올바르지 않은 괄호입니다.

'(' 또는 ')' 로만 이루어진 문자열 s가 주어졌을 때, 문자열 s가 올바른 괄호이면 true return 하고, 올바르지 않은 괄호이면 false return 하는 solution 함수를 완성해 주세요.

 

제한사항

문자열 s의 길이 : 100,000 이하의 자연수

문자열 s '(' 또는 ')' 로만 이루어져 있습니다.

 

입출력 예

answer
"()()" true
"(())()" true
")()("  false
"(()("  false

 

입출력 예 설명

입출력 예 #1,2,3,4

문제의 예시와 같습니다.

 

문제 해결 방법

예시를 찬찬히 살펴보자. 

 

'('를 괄호가 열렸다고 표현하고, ')'를 괄호가 닫혔다고 표현하겠다. 

 

괄호가 열려있을 때, 괄호가 열릴수 있음 

괄호가 열려있을 때, 괄호가 닫힐 수 있음

괄호가 닫혔을 때 괄호를 열든 다시 닫든 할 수 있지만, 괄호가 닫히는것 부터 시작하면 안됨

 

이건 완전히 스택이다. 

 

괄호가 열려있다는 것을 push, 닫힌다는 것을 pop으로 표현한다고 했을 때 위에 있는 말에 대입 해보자. 

 

push할 때, push할 수 있음 

push할 때, pop할 수 있음

pop후에 push든 pop이든 할 수 있지만, pop부터 시작하면 안됨

 

이건 완전히 스택이다. 

 

pop부터 시작하면 안되는 이유는 스택에서, 스택이 비었을때 pop을 하면 더이상 pop할 게 없어서 따로 처리를 안해주면 오류가 생긴다. 

 

s에 대한 조회가 끝났을 때 stack에 뭔가 남아있으면 false이다. 

그런데 스택이 비었는데 )가 나오는 경우가 있을 수 있으니, 그럴때는 스택에 뭔가 남아있어서 False하는 경우와 구분하기 위해서 realF라는 변수에 0, 1을 넣어서 체크했다. 

 

코드 구현

def solution(s):
    answer = True
    
# (는 스택에서 push역할을 하고  )는 pop역할을 함 
# 스택이 빈 채로 끝나지 않으면 false임 

    stack = []
    realF= 0
    for i in range(len(s)):
        if s[i] =='(':
            stack.append(1)
        else:
            if len(stack)<1:
                answer= False
                realF = 1
                break
            else:
                stack.pop()
    
    if stack or realF == 1:
        answer = False
    else:
        answer = True
    
    return answer

 

시간/공간 복잡도

최악의 경우 n 임 

 

최적화 및 개선

어디를 최적화 해야하는지 잘 모르겠다! 

 

어려웠던 점

없었다 ^__^

+ Recent posts