•
회의 날짜: 2022/01/10
•
회의 장소: discord 라운지
•
참석자: 김솔배, 구연지, 안지영, 김재근
[회고 사진]
[문제]
[이번 스터디 공부한 내용]
김솔배
주식가격
Queue/Stack으로 분류된 문제이다.
처음에 어떻게 Queue 또는 Stack으로 접근할 수 있지? 라는 생각때문에 시작을 못하는거 같아서
일단 for문으로 풀어보자는 생각을 했다.
그런데 시간초과 없이 통과를 해버렸다.
어떻게 Queue 또는 Stack을 사용하는지 더 공부해 봐야겠다.
public class Solution {
public int[] solution(int[] prices) {
int[] answer = new int[prices.length];
for (int i = 0; i < prices.length; i++) { //price 길이만큼 반복
//종료조건 : 마지막은 무조건 0이다. ArraysOutOfIndex 방지
if(i == prices.length - 1) {
answer[i] = 0;
break;
}
int cnt = 0; // answer[i]의 갯수
int num = prices[i]; // 비교할 기준 숫자
for (int j = i + 1; j < prices.length; j++) {
if (num <= prices[j]) cnt++; //다음 숫자와 비교해서 다음숫자가 더 크다면 ++
else if (num > prices[j]){ // 작다면 ++후 종료
cnt++;
break;
}
}
answer[i] = cnt;
}
return answer;
}
public static void main(String[] args) {
Solution solution = new Solution();
Scanner sc = new Scanner(System.in);
int[] prices = {1, 2, 3, 2, 3};
System.out.println(Arrays.toString(solution.solution(prices)));
}
}
Java
복사
프로그래머스는 정답을 맞추면 다른사람의 풀이를 볼 수 있다.
그중 깔끔한 코드를 더 공부해보았다.
나는 정답이 될 인자들을 직접 구해가며 계산했지만, 아래 코드는 answer[i]에서 바로 정답을 계산해서 코드가 훨씬 깔끔하다.
public class SolutionBestCode {
public int[] solution(int[] prices) {
int len = prices.length;
int[] answer = new int[len];
int i, j;
for (i = 0; i < len; i++) {
for (j = i + 1; j < len; j++) {
answer[i]++;
if (prices[i] > prices[j])
break;
}
}
return answer;
}
public static void main(String[] args) {
SolutionBestCode solution = new SolutionBestCode();
int[] prices = {1, 2, 3, 2, 3};
System.out.println(Arrays.toString(solution.solution(prices)));
}
}
Java
복사
수들의 합2
처음에는 DFS나 순열, 조합으로 풀 수 있을거 같아서 많은 시도를 해보았다.
그런데 중복되는 계산들을 어떻게 처리할지 몰라서 우선 for문으로 접근해 보았다.
그런데 역시 시간초과는 나지 않고 해결되어버렸다.
그러나 아래 코드는 시간복잡도가 O(n2)이다.
두번째 반복문에서 j의 조건과 if문의 break로 조금 시간을 줄일수는 있겠지만 여전히 O(n2)일것이다.
public class MainOn2 {
public static void main(String[] args) {
/**
* 시간복잡도가 O(n2)이다.
*/
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) arr[i] = sc.nextInt();
int cnt = 0;
for (int i = 0; i < arr.length; i++) {
int sum = 0;
for (int j = i; j < arr.length; j++) {
if(sum < m) sum += arr[j];
if (sum == m) {
cnt++;
break;
}
}
}
System.out.println(cnt);
}
}
Java
복사
이렇게 연속되는 값을 계산하는 경우에는 투포인터라는 알고리즘을 사용하면 된다고 한다.
그래서 배울겸 공부를 해보았다.
public class Main {
/**
* 투 포인터로 : 시간복잡도 최대 O(n)이다.
* 시간복잡도 : Sum과 m을 비교하는 횟수 = start와 end가 움직이는 횟수
* 최대로 움직여봤자 2n번 움직이므로 O(n)이 된다.
*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) arr[i] = sc.nextInt();
/**
* 4 2
* 1 1 1 1
*/
// start : 연속구간의 시작, end : 연속구간의 끝
int start = 0;
int end = 0;
int sum = 0; //연속되는 구간의 합
int cnt = 0; //정답인 갯수
while (true) {
if (sum >= m) {
sum -= arr[start++];
} else if (end >= n) { //종료조건
break;
} else { //m보다 sum이 더 작으면
sum += arr[end++];
}
if (sum == m) cnt++;
}
System.out.println(cnt);
}
}
Java
복사
구연지
1. 주식가격
특정 숫자에서 시작해서 오른쪽으로 가면서 자신 보다 작은 숫자가 나오면 count 더하기를 멈춘다.
(1) pop left 이용하기 → 효율성 테스트 통과X
from collections import deque
def solution(prices):
answer = [0]*len(prices)
for i in range(len(prices)):
stack = deque(prices[i:])
count = 0
critical = stack.popleft()
while(len(stack)>0):
value = stack.popleft()
if(value >= critical):
count += 1
else:
count += 1
break
answer[i] = count
return answer
print(solution([1,2,3,2,3])) # 4, 3, 1, 1, 0
print(solution([1,2,3,4,2,3])) # 5, 4, 2, 1, 1, 0
print(solution([1,2,3,2,1,4,2,3])) # 7, 3, 1, 1, 3, 1, 1, 0
Python
복사
매번 deque를 선언하고 popleft를 진행하여 시간 초과 문제가 발생 → deque 선언과 pop을 할 시간을 제거할 수 있는 방법이 필요
(2) index를 이용하기
def solution(prices):
answer = [0]*len(prices)
for i in range(len(prices)):
pointer = i # pointer는 비교하고 싶은 숫자의 index를 나타냄
count = 0
critical = prices[pointer]
pointer += 1
while(pointer < len(prices)):
if (prices[pointer] >= critical):
pointer += 1
count += 1
else:
count += 1
break
answer[i] = count
return answer
print(solution([1,2,3,2,3])) # 4, 3, 1, 1, 0
print(solution([1,2,3,4,2,3])) # 5, 4, 2, 1, 1, 0
print(solution([1,2,3,2,1,4,2,3])) # 7, 3, 1, 1, 3, 1, 1, 0
Python
복사
2. 수들의 합 2
(1) index 이용하기
# 시간 초과
import sys
factors = sys.stdin.readline().split(" ")
length = int(factors[0])
goal = int(factors[1])
nums = list(map(int, sys.stdin.readline().split(" ")))
counts = 0
for i in range(length):
pointer = i
sum = 0
while(pointer < length):
sum += nums[pointer]
if(sum == goal):
counts += 1
break
elif (sum > goal):
break
else:
pointer += 1
print(counts)
Python
복사
while 때문인가? → for 이용해보기
(2) 이중 for문 → 시간 초과
import sys
length, goal = map(int, sys.stdin.readline().split(" "))
nums = list(map(int, sys.stdin.readline().split(" ")))
counts = 0
for i in range(length):
sum = 0
for pointer in range(i, length):
sum += nums[pointer]
if(sum == goal):
counts += 1
break
elif (sum > goal):
break
print(counts)
Python
복사
(3) 투 포인터 알고리즘 - index 업데이트 하는 것 주의하기!
import sys
length, goal = map(int, sys.stdin.readline().split(" "))
nums = list(map(int, sys.stdin.readline().split(" ")))
counts = 0
left_idx = -1
right_idx = -1
sum = 0
while (True):
if(right_idx < length -1):
if(sum < goal):
right_idx += 1
sum += nums[right_idx]
else:
left_idx += 1
sum -= nums[left_idx]
else:
left_idx += 1
sum -= nums[left_idx]
if(sum == goal):
counts += 1
if (right_idx >= length -1) and (left_idx >= length -1):
break
print(counts)
Python
복사
시간 복잡도가 O(N)
안지영
문제 1 - 주식 가격
먼저 해시를 사용해서 각 가격별로 index를 저장해놓고, 특정 시점의 가격에 대해서 더 높은 가격이 해시에 존재하면 제거하면서 answer를 업데이트하는 방식으로 접근하였다. 하지만 제출했을 때 시간초과가 났다. 개인적으로 아래에 소개할 방법보다 시간이 덜 걸릴것이라 예상했지만 예상이 틀렸다. 다른 분들 말대로 for loop 두번 안에 while loop까지 들어가서 그런건가 싶기도 하다.
# 해시 - 시간초과
from collections import defaultdict
def solution(prices):
N = len(prices)
MAX_PRICE = max(prices)
answer = [0] * N
stock = defaultdict(list)
stock[prices[0]].append(0)
for i in range(1, N-1):
for key in stock:
if prices[i] >= key:
continue
while stock[key]!=[]:
idx = stock[key].pop()
answer[idx] = i - idx
stock[prices[i]].append(i)
for key in stock:
while stock[key]!=[]:
idx = stock[key].pop()
answer[idx] = N - 1 - idx
return answer
prices = [1,2,3,2,3]
print(solution(prices))
Python
복사
아래의 방법으로 풀었을 때는 시간초과가 나지 않았다. 처음에 직관적으로 떠오른 풀이 방법이였는데 시간초과가 날 것 같아서 위의 방법을 생각해낸것이었는데, 결과적으로는 접근이 틀렸던 것 같다.
# 완전탐색 - 성공
def solution(prices):
N = len(prices)
answer = [0] * N
for i in range(N):
for j in range(i+1, N):
answer[i] += 1
if prices[i] > prices[j]:
break
return answer
print(solution([1,2,3,2,3]))
Python
복사
문제 2 - 수들의 합 2
위의 주식 문제를 교훈 삼아 가장 처음에 직관적으로 떠올랐던 아래의 풀이를 제출해보았더니, 이번 케이스에서는 시간초과가 났다.
# 시간초과
N, M = map(int, input().split())
A = list(map(int, input().split()))
count = 0
for i in range(N):
sum_of_num = 0
for j in range(i,N):
sum_of_num += A[j]
if sum_of_num > M:
break
elif sum_of_num == M:
count += 1
break
print(count)
Python
복사
도저히 모르겠어서 검색 찬스를 사용하였다. 투 포인터를 사용하는 방법이었는데, 이해가 안되는 것은 아니지만 생소한 방법이라서 연습이 더 필요할 것 같다. 팀원분들 말씀으로는 투 포인터를 사용하는 문제가 꽤 있다고 하니 다양한 문제를 풀어봐야 할 것 같다.
# 2003 https://www.acmicpc.net/problem/2003
# 완료
N, M = map(int, input().split())
A = list(map(int, input().split()))
count = 0
sum_of_num = A[0]
left = 0
i = 1
while(True):
if sum_of_num == M:
count+=1
sum_of_num -= A[left]
left += 1
elif sum_of_num > M:
sum_of_num -= A[left]
left += 1
else:
if i < N:
sum_of_num += A[i]
i +=1
else:
break
print(count)
Python
복사
김재근
백준 2003
분명… 제출해서 정답 확인을 했었는데…
스터디 시간에 발표할 때 다시 돌려보니 정답이 나오지 않았습니다…
그래서 스터디 시간에 급하게 다시 코드를 짰는데…도
정답이 나오지 않았습니다… ㅠ
start , end index 가 서로 겹치는 부분을 처리하지 못했기 때문인데,
그 부분은 연지님의 도움으로 해결했습니다..!
앞으로 스터디하면서 같은 일이 발생하지 않게 제대로 코드를 짜와야겠습니다 ㅠ
def solution(N, M, arr):
start, end = 0, 0
total = arr[0]
cnt = 0
while True:
if total < M:
end += 1
if end >= N:
break
total += arr[end]
elif total == M :
cnt += 1
total -= arr[start]
start += 1
else:
total -= arr[start]
start += 1
return cnt
N, M = map(int, input().split())
arr = list(map(int, input().split()))
print(solution(N, M, arr))
Python
복사
[어려웠던 부분]
•
시간복잡도를 계산하는것과, for문이 아닌 다른 해법들을 찾는게 어려웠다.
Plain Text
복사
•
백준 문제를 풀 때 two pointer라는 알고리즘을 떠올려야 했던 부분이 어려웠던 것 같다.
문제를 보면 풀이를 외워야하는 수준인건가... 라는 생각도 들었던 것 같다.
Plain Text
복사
•
1. 틀렸을 때보다 시간초과가 날 때가 더 당황스러운 것 같다. 접근 방식을 바꾸어야 한다는 뜻이니까 생각해내기가
더 어려운 것 같다.
2. 투 포인터 문제에서 while 루프의 탈출 조건을 제대로 계획하지 않으면 무한루프가 나기 쉬운 것 같다.
Plain Text
복사
•
two pointer 문제는 몇 번 풀어본적이 있었는데
역시 예외 부분을 떠올리는게 쉽지 않은 것 같습니다..
이 부분을 조금 더 신경 써서 공부해야겠습니다..!
Plain Text
복사
[금주의 꿀팁 & 인사이트!]
•
문제를 해결할때 어떻게하면 조금 더 효율적인 코드를 작성할 수 있을까?
어떻게 하면 더 깔끔한 코드를 작성할 수 있을까? 라는 생각을 하자!
Plain Text
복사
•
deque()를 여러번 선언해야하는 경우는 시간이 더 오래걸릴 수 있으니 주의하자!
Plain Text
복사
•
늘 효율성을 생각하면서 코드를 짜자. 먼저 직관적으로 생각나는 코드를 작성해보고, 이후에 되지 않으면
다른 방법을 생각해보는 방향으로 접근하자.
Plain Text
복사
•
계속해서 코드를 작성하면서 느낀점이 반복문으로만 짜려는 느낌적 느낌이 있는데,
해당부분을 다른 방법이 있다면 다르게도 짜보는 노력을 해봐야겠습니다!
그리고 시간복잡도를 계산하는 노력을 하면 자연스럽게 좋은 코드가 나올 것 같다는 생각을 하게 되었습니다!
Plain Text
복사
[금주의 느낀 점]
•
일단 풀고보면 해결이 될때도 있다.
어렵다고 시작하지 않을때도 있는데 그러지 말고 할수있는한 최선을 다해보자
Plain Text
복사
•
저번 주랑 비슷하게 문제 유형에 따라 풀이를 정리하는 것이 필요하다는 것을 절실히 느꼈다.
Plain Text
복사
•
시간복잡도를 더 생각하면서 코드를 짜는 습관을 길러야 할 것 같다.
Plain Text
복사
•
생각대로 짠 로직에서 예외부분은 없는지 있다면 어떻게 처리해야할지에 대한
생각을 계속해서 하는 노력을 해야겠습니다 ㅠ
Plain Text
복사