File tree Expand file tree Collapse file tree 4 files changed +192
-0
lines changed
non-overlapping-intervals
number-of-connected-components-in-an-undirected-graph
remove-nth-node-from-end-of-list Expand file tree Collapse file tree 4 files changed +192
-0
lines changed Original file line number Diff line number Diff line change 1+ """
2+ 구간이 겹쳐 삭제해야 되는 최소 구간의 수를 반환해라
3+ -> Greedy
4+ -> '겹치지 않게 최대한 많은 구간을 남기고, 나머지를 제거'
5+
6+ 문제 풀이
7+ 1. 끝나는 시간 기준으로 오름차순 정렬
8+ 2. 이전 구간의 끝과 현재 구간의 시작을 비교
9+ 3. 겹치면 현재 구간을 제거
10+
11+ TC: O(n log n), 정렬 O(n log n) + 모든 interval 한 번씩 순회 O(n)
12+ SC: O(1)
13+ """
14+
15+ from typing import List
16+
17+ class Solution :
18+ def eraseOverlapIntervals (self , intervals : List [List [int ]]) -> int :
19+ # 끝나는 시간이 빠른 순으로 정렬
20+ # -> 일찍 끝나는 구간을 선택하면, 이후에 더 많은 구간을 넣을 수 있는 여지가 커짐!
21+ intervals .sort (key = lambda x : x [1 ])
22+
23+ # 첫 구간 선택
24+ prev_end = float ('-inf' ) # 음의 무한대로 비교의 기준값 가장 작게 설정 -> 첫 번째 구간 무조건 선택됨
25+ count = 0
26+
27+ # 하나씩 검사
28+ for start , end in intervals :
29+ if start >= prev_end :
30+ # 겹치지 않음 -> 그대로 유지
31+ prev_end = end
32+ else :
33+ # 겹침 -> 하나 제거
34+ count += 1
35+
36+ return count
Original file line number Diff line number Diff line change 1+ /**
2+ * TC: O(N + E), N: 노드의 개수, E: 간선의 개수
3+ * SC: O(N + E)
4+ */
5+
6+ // DFS
7+ function countComponentsDFS ( n : number , edges : number [ ] [ ] ) : number {
8+ const graph : number [ ] [ ] = Array . from ( { length : n } , ( ) => [ ] ) ;
9+
10+ // 그래프 초기화
11+ for ( const [ u , v ] of edges ) {
12+ graph [ u ] . push ( v ) ;
13+ graph [ v ] . push ( u ) ;
14+ }
15+
16+ const visited = new Set < number > ( ) ;
17+
18+ function dfs ( node : number ) {
19+ visited . add ( node ) ;
20+ for ( const neighbor of graph [ node ] ) {
21+ if ( ! visited . has ( neighbor ) ) {
22+ dfs ( neighbor ) ;
23+ }
24+ }
25+ }
26+
27+ let components = 0 ;
28+ for ( let i = 0 ; i < n ; i ++ ) {
29+ if ( ! visited . has ( i ) ) {
30+ components ++ ;
31+ dfs ( i ) ;
32+ }
33+ }
34+
35+ return components ;
36+ }
37+
38+ // BFS
39+ function countComponentsBFS ( n : number , edges : number [ ] [ ] ) : number {
40+ const graph : number [ ] [ ] = Array . from ( { length : n } , ( ) => [ ] ) ;
41+
42+ // 그래프 초기화
43+ for ( const [ u , v ] of edges ) {
44+ graph [ u ] . push ( v ) ;
45+ graph [ v ] . push ( u ) ;
46+ }
47+
48+ const visited = new Set < number > ( ) ;
49+ let components = 0 ;
50+
51+ for ( let i = 0 ; i < n ; i ++ ) {
52+ if ( ! visited . has ( i ) ) {
53+ components ++ ;
54+ const queue : number [ ] = [ i ] ;
55+
56+ while ( queue . length > 0 ) {
57+ const node = queue . shift ( ) ;
58+ if ( node === undefined ) continue ;
59+ if ( visited . has ( node ) ) continue ;
60+ visited . add ( node ) ;
61+
62+ for ( const neighbor of graph [ node ] ) {
63+ if ( ! visited . has ( neighbor ) ) queue . push ( neighbor ) ;
64+ }
65+ }
66+ }
67+ }
68+
69+ return components ;
70+ }
Original file line number Diff line number Diff line change 1+ """
2+ 뒤에서 n번째 노드를 없애고, linked list head를 반환해라
3+ TC: O(N), 리스트 한 번 순회
4+ SC: O(1), 포인터 2개만 사용
5+ """
6+
7+ from typing import Optional
8+
9+ # Definition for singly-linked list.
10+ class ListNode :
11+ def __init__ (self , val = 0 , next = None ):
12+ self .val = val
13+ self .next = next
14+
15+
16+ class Solution :
17+ def removeNthFromEnd (self , head : Optional [ListNode ], n : int ) -> Optional [ListNode ]:
18+ # dummy node를 head 앞에 두어 edge case(head 삭제 등) 처리
19+ dummy = ListNode (0 , head )
20+ first = dummy
21+ second = dummy
22+
23+ # first를 n+1칸 먼저 이동 -> 두 포인터 사이 간격이 n
24+ for _ in range (n + 1 ):
25+ first = first .next
26+
27+ # first가 끝에 도달할 때까지 두 포인터 함께 전진
28+ while first :
29+ first = first .next
30+ second = second .next
31+
32+ # second의 다음 노드가 삭제 대상이므로 연결 건너뛰기
33+ second .next = second .next .next
34+
35+ # 실제 head는 dummy.next에 있음
36+ return dummy .next
Original file line number Diff line number Diff line change 1+ from typing import Optional
2+
3+ # Definition for a binary tree node.
4+ class TreeNode :
5+ def __init__ (self , val = 0 , left = None , right = None ):
6+ self .val = val
7+ self .left = left
8+ self .right = right
9+
10+ """
11+ 재귀 풀아
12+ TC: O(N), 양 트리의 각 노드를 상대로 재귀함수를 딱 1번씩만 호출하기 때문
13+ SC: O(N), 공간복잡도 = 콜스택의 최대 높이(노드의 수)
14+ """
15+ class Solution :
16+ def isSameTree (self , p : Optional [TreeNode ], q : Optional [TreeNode ]) -> bool :
17+ # 둘 다 null이면 True 반환
18+ if not p and not q :
19+ return True
20+ # 둘 중 하나면 null이면 False 반환
21+ if not p or not q :
22+ return False
23+ # val이 서로 다르면 탐색 중단, False 반환
24+ if p .val != q .val :
25+ return False
26+ # 현재 node의 val이 같다면, 좌우측 자식 트리도 같은지 확인 -> 재귀 호출
27+ return self .isSameTree (p .left , q .left ) and self .isSameTree (p .right , q .right )
28+
29+
30+ """
31+ 스택 풀이
32+ TC: O(N)
33+ SC: O(N)
34+ """
35+
36+ class Solution :
37+ def isSameTree (self , p : Optional [TreeNode ], q : Optional [TreeNode ]) -> bool :
38+ stack = [(p , q )]
39+
40+ while stack :
41+ p , q = stack .pop ()
42+ if not p and not q :
43+ continue
44+ if not p or not q :
45+ return False
46+ if p .val != q .val :
47+ return False
48+ stack .append ((p .left , q .left ))
49+ stack .append ((p .right , q .right ))
50+ return True
You can’t perform that action at this time.
0 commit comments