[코딩테스트 합격자 되기 스터디] 2주차 - 스택과 큐 (7.14 ~ 7.20)
코딩테스트 합격자 되기 스터디 2주차
강의 보기 -> 해당되는 부분 책 다시 읽기 -> 블로그 정리
강의는 C++로 되어 있지만 개념적인 내용이라 언어 상관 없이 보고 코드는 각 언어에 맞게 바꾸면 된다.
참고 강의 및 책
인프런 : 코딩테스트 합격자 되기 파이썬, C+_+ 저자님 인프런 강의 링크
Youtube : 코딩테스트 합격자 되기 파이썬, C+_+ 저자님 Youtube 링크
종이책 : 코딩테스트 합격자 되기 파이썬 편
종이책 : 코딩테스트 합격자 되기 C++ 편
종이책 : 코딩테스트 합격자 되기 자바스크립트 편
종이책 : 코딩테스트 합격자 되기 자바 편
ADT란?
- ADT(Abstract Data Type) : 추상 데이터 타입의 약어
- 세부 사항을 숨기고 사용자에게 필요한 기능만 명시
- 필요한 연산만 정의함으로써 자료구조 동작 자체에 집중할 수 있다.
- 전화번호부
- put(name, phone)
- get(name)
- remove(name)
- contains(name)
- size()
- 위 기능들같이 필요한 기능만 사용할 수 있다.
스택의 개념
- LIFO(Last In First Out) : 가장 최근에 들어간 원소가 가장 먼저 출력된다.
- FILO(First In Last Out) : 가장 먼저 들어간 원소가 마지막에 출력된다.
- 가장 최근에 들어온 원소를 알 수 있다.
- 가장 최근에 들어온 원소순으로 출력된다.
스택의 ADT
스택의 예시코드
- C++ -> JAVA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.Stack; public class Main { public static void main(String[] args) { Stack<Integer> s = new Stack<>(); s.push(1); // 스택 s에 데이터 1 추가, 시간 복잡도: O(1) s.push(2); s.push(3); System.out.println(s.peek()); // peek(), 스택의 맨 위 원소 확인, 시간 복잡도: O(1) s.pop(); // 스택의 맨 위 원소 제거, 스택이 비어 있으면 예외 발생, 시간 복잡도: O(1) System.out.println("Top element after pop: " + s.peek()); if (!s.isEmpty()) { // 스택이 비어있는지 확인, 시간 복잡도: O(1) System.out.println("Stack is not empty"); } // !연산이 있기 때문에 스택에 데이터가 있을 때 출력문 실행 System.out.println("Stack size: " + s.size()); // 스택의 크기 확인, 시간 복잡도: O(1) while (!s.isEmpty()) { System.out.println("Popping element: " + s.peek()); s.pop(); // 스택데이터를 모두 제거할 때 까지 실행, 시간복잡도: O(1) } if (s.isEmpty()) { System.out.println("Stack is empty after popping all elements"); } } }
스택의 사용예시1
스택의 사용예시2
스택의 사용예시3
큐의 개념
- FIFO(First In First Out) : 가장 먼저 들어간 원소가 가장 먼저 나오는 자료구조
큐의 ADT
큐의 예시코드
- C++ -> JAVA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.util.ArrayDeque; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<Integer> q = new ArrayDeque<>(); q.offer(1); // offer: 큐의 끝에 요소 추가, 시간복잡도: O(1) q.offer(2); // offer 대신 add도 가능하다. q.offer(3); System.out.println("Front element: " + q.peek()); // peek: 큐의 첫 번째 요소에 접근, O(1) q.poll(); // poll: 큐의 첫 번째 요소 제거, O(1) System.out.println("Front element after poll: " + q.peek()); if (!q.isEmpty()) { System.out.println("Queue is not empty"); } System.out.println("Queue size: " + q.size()); // size: 큐의 크기 확인, O(1) } }
큐의 사용예시1
- 줄 서기
![]()
- 작가 pikisuperstar 출처 Freepik
![]()
![]()
- 제일 앞에 줄 서있는 사람부터 계산을 하고 나간다.
큐의 사용예시2
- 요세푸스 문제
- N명의 사람들이 원형으로 둘러앉고, 1~N으로 번호를 매긴다.
- 시작 위치부터 K번째 사람 제거
- 제거한 위치부터 다시 K번째 사람 제거
- 3번째 과정을 한 명이 남을 때 까지 반복
![]()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.ArrayDeque; import java.util.Queue; public class Main { public static int josephus(int N, int K) { Queue<Integer> q = new ArrayDeque<>(); for (int i = 1; i <= N; i++) { // 큐를 초기화하고 1부터 N까지의 요소를 삽입합니다. q.add(i); // 시간복잡도: O(N) } while (q.size() > 1) { // 큐의 크기가 1이 될 때까지 반복합니다. // 첫 번째 K-1개의 요소를 큐의 뒤로 이동시킵니다. for (int i = 0; i < K - 1; i++) { q.add(q.poll()); // 시간복잡도: O(N * K) } q.poll(); // K번째 요소를 제거합니다. } return q.peek(); } public static void main(String[] args) { int N = 5; // 예시: 5명의 사람이 있을 때 int K = 2; // 예시: 매 2번째 사람을 제거할 때 System.out.println("The survivor is: " + josephus(N, K)); } }
정리
- 스택(Stack)
- LIFO
- 함수 호출 관리
- 페이지 탐색
- 괄호 짝 맞추기
- 가장 최근 원소를 봐야하는 경우에 사용
- DFS, 백트래킹에서 사용
- 큐(Queue)
- FIFO
- 줄 서기
- 요세푸스
- 들어온 순서대로 나갈 때 사용
- BFS에서 사용
괄호 회전하기 문제 풀이
- 괄호 회전하기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public static int solution(String s) { int count = 0; int n = s.length(); for (int i = 0; i < n; i++) { if (isValid(s, i)) { count++; } } return count; } private static boolean isValid(String s, int start) { Stack<Character> stack = new Stack<>(); int n = s.length(); for (int i = 0; i < n; i++) { char c = s.charAt((start + i) % n); if (c == '(' || c == '{' || c == '[') { stack.push(c); } else { if (stack.isEmpty()) { return false; } char top = stack.pop(); if (!isMatchingPair(top, c)) { return false; } } } return stack.isEmpty(); } private static boolean isMatchingPair(char open, char close) { return (open == '(' && close == ')') || (open == '{' && close == '}') || (open == '[' && close == ']'); }- 시간복잡도: O(N^2)
주식 가격 문제 풀이
- 주식 가격
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public int[] solution(int[] prices) { ArrayDeque<Integer> stack = new ArrayDeque<>(); int length = prices.length; int[] answer = new int[length]; stack.push(0); for (int i = 1; i < length; i++) { while(!stack.isEmpty() && prices[i] < prices[stack.peek()]) { int pop = stack.pop(); answer[pop] = i - pop; } stack.push(i); } while(!stack.isEmpty()) { int pop = stack.pop(); answer[pop] = length - 1 - pop; } return answer; }- 시간복잡도: O(N)
영어 끝말잇기 문제 풀이
- 영어 끝말잇기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public int[] solution(int n, String[] words) { Set<String> wordSet = new HashSet<>(); wordSet.add(words[0]); for (int i = 1; i < words.length; i++) { String prevWord = words[i - 1]; String currentWord = words[i]; if (prevWord.charAt(prevWord.length() - 1) != currentWord.charAt(0) || wordSet.contains(currentWord)) { int player = (i % n) + 1; int turn = (i / n) + 1; return new int[]{player, turn}; } wordSet.add(currentWord); } return new int[]{0, 0}; }- 시간복잡도: O(N)
베스트 앨범 문제 풀이
- 베스트 앨범
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 static class Song { int plays; int index; Song(int plays, int index) { this.plays = plays; this.index = index; } } public int[] solution(String[] genres, int[] plays) { Map<String, Integer> genrePlayCount = new HashMap<>(); Map<String, List<Song>> songsByGenre = new HashMap<>(); for (int i = 0; i < genres.length; i++) { String genre = genres[i]; int play = plays[i]; genrePlayCount.put(genre, genrePlayCount.getOrDefault(genre, 0) + play); songsByGenre.putIfAbsent(genre, new ArrayList<>()); songsByGenre.get(genre).add(new Song(play, i)); } List<String> sortedGenres = new ArrayList<>(genrePlayCount.keySet()); sortedGenres.sort((a, b) -> genrePlayCount.get(b) - genrePlayCount.get(a)); List<Integer> bestAlbum = new ArrayList<>(); for (String genre : sortedGenres) { List<Song> songs = songsByGenre.get(genre); songs.sort((a, b) -> b.plays == a.plays ? a.index - b.index : b.plays - a.plays); for (int i = 0; i < Math.min(2, songs.size()); i++) { bestAlbum.add(songs.get(i).index); } } return bestAlbum.stream().mapToInt(i -> i).toArray(); }- 못 풀었다… ↑ 다른 사람의 풀이 ↑
- 시간복잡도: O(n log n)