Skip to content

[3주차] 이혜원 #34

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Sep 28, 2024
45 changes: 45 additions & 0 deletions BOJ/10001-15000번/HW_13335.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 시간 복잡도 : n, L <= 1,000 단순 구현 고려x
// 모든 트럭들이 다리를 건너는 최단시간 구하기
// 사용할 자료구조 : 큐 (먼저온 트럭이 먼저 나감),
import java.util.*;
import java.io.*;
public class HW_13335 {
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());

int n = Integer.parseInt(st.nextToken()); // 트럭의 수
int w = Integer.parseInt(st.nextToken()); // 다리의 길이
int L = Integer.parseInt(st.nextToken()); // 다리의 최대 하중

// 반복문을 어떻게 작성하지?
st = new StringTokenizer(br.readLine());
Queue<Integer> trucks = new LinkedList<>(); // 대기 중인 트럭 큐
for(int i=0; i<n; i++){
trucks.add(Integer.parseInt(st.nextToken())); // 입력 받음
}

Queue<Integer> bridge = new LinkedList<>(); // 다리위 트럭들 큐
for(int i=0; i<w; i++){
bridge.add(0); // 처음에는 다리위에 트럭이 없기 때문에 0으로 초기화
}

int cnt =0; // 다리 건너는 시간
int weightBridge = 0; // 현재 다리 무게

while (!bridge.isEmpty()) { // 다리 큐가 빌 때까지 반복
cnt++; // 소요 시간++
weightBridge -= bridge.poll(); // 트럭이 다리에서 내릴 때 (현재 다리 무게) - (다리 위 트럭 무게)
if(!trucks.isEmpty()){ // 트럭 큐가 빌 때가지 반복
if(trucks.peek() + weightBridge <= L){ // (현재 트럭 무게) + (현재 다리 무게) <= (다리 하중)
weightBridge += trucks.peek(); // 트럭이 다리 위에 있음 (다리 무게) + (현재 트럭 무게)
bridge.add(trucks.poll()); // 트럭 무게를 다리에 추가
} else{
bridge.add(0); // L(다리 하중)보다 클 경우 트럭을 추가 하지않음
}
}
}
System.out.println(cnt);
}
}

23 changes: 23 additions & 0 deletions BOJ/15001-20000번/HW_15989.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import java.io.*;
// 시간 복잡도 : n<=10,000, O(N)
// n을 1, 2, 3의 합으로 나타내는 방법
public class HW_15989 {
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int dp[] = new int[10001];
dp[0] =1; // 초기값 선언

for(int i=1; i<=3; i++) {
for(int j=i; j<10001; j++) {
dp[j] += dp[j-i];
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

점화식을 구하는데 많은 시간을 소요했는데,, 혜원님 코드보니깐 완전 잘 이해가 되었습니다 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 풀이 참고해서 푼거긴한데 이해가 오래 걸렸습니다,,,👍


int T = Integer.parseInt(br.readLine()); // 테스트 케이스 개수 T
for(int i=0; i<T; i++) {
int N = Integer.parseInt(br.readLine());
System.out.println(dp[N]);
}
br.close();
}
}
66 changes: 66 additions & 0 deletions BOJ/15001-20000번/HW_18404.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

// 시간 복잡도 : O(V+E)
// 각 상대편 말을 잡기 위한 나이트의 최소 이동 수
// BFS
public class HW_18404 {
static int N, M, X, Y;
static int[] dx = {-2, -2, -1, -1, 1, 1, 2, 2};
static int[] dy = {-1, 1, -2, 2, -2, 2, -1, 1};
static int[][] visited;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
StringBuilder sb = new StringBuilder();
// 각 상대편 말을 잡기 위한 최소 이동 수
N = Integer.parseInt(st.nextToken()); // N * N
M = Integer.parseInt(st.nextToken()); // 상대편 말의 개수

st = new StringTokenizer(br.readLine());
X = Integer.parseInt(st.nextToken()); // 나이트의 위치 X
Y = Integer.parseInt(st.nextToken()); // 나이트의 위치 Y

visited = new int[N + 1][N + 1];

for(int i=1; i<N+1; i++){
Arrays.fill(visited[i], -1); // 카운트 및 방문여부 체크를 위한 초기화
}
Bfs();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 말의 위치를 입력받고, bfs하는 순서로 했는데,

bfs먼저 해서 모든 위치에 대해 몇 번째에 이동할 수 있는지 확인하고, 이후에 말의 위치에 대해 몇 번째인지 출력해도 되군요?!! 😲

역시 문제를 풀 때 정해진건 없는거 같네요 ㅎㅎ.. !!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 이슈 댓글을 방금 봤는데요,
혜원님이 하신 방법은 주어진 말의 정보에 대해 다 찾아도 탐색이 끝날 때 까지 bfs를 계속 하게 되는데,
다른 분들은 말의 위치까지 map에 다 저장한 이후, 말이 있는 위치에 대해 다 찾으면 bfs를 끝내줘서 이 부분에서 메모리, 시간이 차이나는 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 그래서 그런거였군요!! 저는 dx, dy를 이차원 배열로 선언해서 그런가 싶어서 일차원배열로 변경 해봤었는데,
오히려 이차원배열로 푼게 시간이 조금 더 빨랐어요 ㅎ,, 다른 분들처럼 탐색이 끝나면 bfs가 멈추는게 더 효율적인 것 같습니다!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 이 부분에 대해서궁금해서 여러 방면으로 시도해봤습니다!
그나마 유의미하게 차이를 보인게

// 경계 체크
if(nX < 1 || nY < 1 || nX > N || nY >N){
    continue;
}

OR연산을 AND연산으로 치환해주니 40ms정도 개선되는 것 같더라구요
OR연산은 TRUE가 나올 때까지 연산해서 그런가..봅니다🤔 신기하네요

아니면 백준 컴파일러 차이일 수도!

// 상대편 말의 위치 (A, B)
for(int i=0; i<M; i++){
st = new StringTokenizer(br.readLine());
int A = Integer.parseInt(st.nextToken());
int B = Integer.parseInt(st.nextToken());
sb.append(visited[A][B]).append(' ');
}
System.out.println(sb.toString());
}
private static void Bfs(){
Queue<Integer> queue = new LinkedList<>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좌표의 위치는 클래스나 배열로 표현하는게 좋을 것 같다고 생각합니다!

queue.add(X);
queue.add(Y);
visited[X][Y] = 0;

while(!queue.isEmpty()){
int X = queue.poll();
int Y = queue.poll();
for(int i=0; i<8; i++){
int nX = X + dx[i];
int nY = Y + dy[i];
if(nX < 1 || nY < 1 || nX > N || nY >N){
continue;
}
if(visited[nX][nY] != -1) {
continue;
}
visited[nX][nY] = visited[X][Y] + 1;
queue.add(nX);
queue.add(nY);
}
}
}
}

70 changes: 70 additions & 0 deletions CodeTree/2017-2018년/HW_디버깅.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// 시간 제한 : 2초,
// 버그를 고치기 위해 필요한 메모리 유실선 개수의 최솟값 출력
import java.io.*;
import java.util.*;
public class HW_디버깅 {
private static int n, m, h, answer;
private static int[][] map;
private static boolean finish = false; // 최소한의 가로선을 찾았는지 여부
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());

n = Integer.parseInt(st.nextToken()); // 고객 수
m = Integer.parseInt(st.nextToken()); // 취약 지점
h = Integer.parseInt(st.nextToken()); // 메모리 유실선

map = new int[h+1][n+1]; // h x n 행렬
int a, b;

for(int i=0; i<m; i++){
st = new StringTokenizer(br.readLine()); // 독립적인 좌표 정보
a = Integer.parseInt(st.nextToken()); // 취약 지점
b = Integer.parseInt(st.nextToken()); // 메모리 유실이 일어난 지점
map[a][b] = 1; // 사다리 오른쪽 이동 가능
map[a][b+1] = 2; // 사다리 왼쪽 이동 가능 (오른쪽으로 이동한 상태이므로 2로 표현)
}

for(int i=0; i<=3; i++){ // 필요한 선의 개수가 3보다 큰 값이거나
answer = i;
dfs(1, 0);
if (finish) break;
}
System.out.println((finish) ? answer : -1); // 버그를 고치는 것이 불가능하다면 -1을 출력
}

private static void dfs(int a, int count){
if(finish) return;
if(answer ==count){
if(check()) finish = true;
return;
}
for(int i=a; i<h+1; i++){
for(int j=1; j<n; j++){
if(map[i][j]==0 && map[i][j+1]==0){ // 가로선이 추가되지 않았으면
map[i][j] =1; // 오른쪽 이동
map[i][j+1] = 2; // 왼쪽 이동
dfs(i, count+1); // 가로선 하나 추가 -> 재귀 호출
map[i][j] = map[i][j+1] =0; // 백트래킹 : 가로선 제거
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

백트래킹을 이용해서 유실선을 추가하고 검사하는 로직을 정확히 이해할 수 있는 정석 코드 같아요!!ㅎㅎㅎ 덕분에 이해가 쏙쏙 됐습니다.

}
}
}
}

private static boolean check(){ // 제대로 이동할 수 있는지 확인
for(int i=1; i<=n; i++){ // 모든 고객에 대해 검사
int a=1, b=i;
while (a <= h) { // 취약 지점의 끝까지 내려가면서 이동
if (map[a][b] == 1) { // 오른쪽으로 이동하는 경우
b++;
} else if (map[a][b] == 2) { // 왼쪽으로 이동하는 경우
b--;
}
a++; // 아래로 한 칸 이동
}
if(b!=i) return false; // 출발위치 != 도착위치
}
return true; // 출발위치 = 도착 위치
}
}

95 changes: 95 additions & 0 deletions CodeTree/2021-2022년/HW_나무 타이쿤.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// 시간 복잡도 : 단순 구현
// m년 이후 남아있는 리브로수의 총 높이의 합
import java.util.*;
import java.io.*;
public class Main {
static int N, M;
static int[][] map;
static int[] dx = {0, -1, -1, -1, 0, 1, 1, 1};
static int[] dy = {1, 1, 0, -1, -1, -1, 0, 1};
static boolean[][] visited;
static int sum; // m년 이후 남아있는 리브로수의 총 높이의 합
public static void main(String[] args) throws IOException{
// 여기에 코드를 작성해주세요.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());

N = Integer.parseInt(st.nextToken()); // 격자의 크기 N
M = Integer.parseInt(st.nextToken()); // 리브로수를 키우는 총 년 수 m
map = new int[N][N];

// 원소 입력 받기
for(int i=0; i<N; i++){
st = new StringTokenizer(br.readLine());
for(int j=0; j<N; j++){
map[i][j] = Integer.parseInt(st.nextToken());
}
}

visited = new boolean[N][N];
// 초기 영양제 위치 (N-1, 0), (N-1, 1), (N-2, 0), (N-2, 1)
visited[N-1][0] = visited[N-1][1] = visited[N-2][0] = visited[N-2][1] = true;

for(int i=0; i<M; i++){
st = new StringTokenizer(br.readLine());
int d = Integer.parseInt(st.nextToken()); // 이동 방향
int p = Integer.parseInt(st.nextToken()); // 이동 칸 수

simulation(d-1, p%N); // 인덱스, 격좌 범위 처리
}

sum =0;
for(int i=0; i<N; i++){
for(int j=0; j<N; j++){
sum += map[i][j];
}
}
System.out.println(sum);
}

public static void simulation(int direction, int pace){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드를 기능마다 나눠서 리팩토링하는 것도 괜찮을 것 같아요!

boolean[][] check = new boolean[N][N];
for(int i=0; i<N; i++){
for(int j=0; j<N; j++){
if(visited[i][j]){
int nx = (i + dx[direction] * pace + N) % N;
int ny = (j + dy[direction] * pace + N) % N;
check[nx][ny] = true;
map[nx][ny]++;
}
}
}
visited = check;

// 대각선 체크
for(int i=0; i<N; i++){
for (int j=0; j<N; j++){
if(visited[i][j]){
for(int d=1; d<8; d+=2){ // 대각선 방향 체크(1, 3, 5, 7)
int nx = i + dx[d];
int ny = j + dy[d];
if(nx<0 || ny <0 || nx >=N || ny >= N){
continue;
}
if(map[nx][ny]>0){ // 대각선에 있으면 ++
map[i][j]++;
}
}
}
}
}

// 높이가 2이상인 리브로수는 잘라냄
for(int i=0; i<N; i++){
for(int j=0; j<N; j++){
if(visited[i][j]){
visited[i][j] = false; // 기존 영양제 없앰
}
else if(map[i][j] >=2){ // 높이가 2이상인 리브로수는 잘라냄
map[i][j] -= 2;
visited[i][j] = true; // 새로운 영양제 배치
}
}
}
}
}
52 changes: 52 additions & 0 deletions Programmers/Level4/HW_43236.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 시간 복잡도 : N=100,000, O(N^2) 불가
// O(100,000 log100,000) = O(M logN)
// 사용할 자료구조 : 이분 탐색

import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;

public class HW_43236 {
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
int[] nArr = new int[N];

StringTokenizer st = new StringTokenizer(br.readLine());
for(int i=0; i<N; i++){
nArr[i] = Integer.parseInt(st.nextToken());
}

Arrays.sort(nArr);// 오름차순 정렬 O(nlog n)

int M = Integer.parseInt(br.readLine());
st = new StringTokenizer(br.readLine());
for(int i=0; i<M; i++){
int target = Integer.parseInt(st.nextToken());
int start = 0;
int end = N -1;
boolean find = false;
while(start <= end){
int mid = (start + end) / 2;
int midIndex = nArr[mid];
if(midIndex > target){
end = mid -1;
}
else if(midIndex < target){
start = mid + 1;
}
else{
find = true;
break;
}
}
if(find){
System.out.println(1);
}
else System.out.println(0);
}

// low, high, target을 mArr 원소로
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- 생일이 3월인 여성 회원의 ID, 이름, 성별, 생년월일을 조회
-- 전화번호가 NULL인 경우는 출력대상에서 제외
-- 회원ID를 기준으로 오름차순 정렬
SELECT MEMBER_ID, MEMBER_NAME, GENDER, DATE_FORMAT(DATE_OF_BIRTH, '%Y-%m-%d') AS DATE_OF_BIRTH
FROM MEMBER_PROFILE
WHERE GENDER = 'W'
AND TLNO is not null
AND MONTH(DATE_OF_BIRTH) = 3
ORDER BY MEMBER_ID;
6 changes: 6 additions & 0 deletions SQL/3주차/HW_상품 별 오프라인 매출 구하기.SQL
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- https://school.programmers.co.kr/learn/courses/30/lessons/131533
SELECT p.PRODUCT_CODE, SUM(p.PRICE * o.SALES_AMOUNT) AS SALES
FROM PRODUCT p
INNER JOIN OFFLINE_SALE o ON p.PRODUCT_ID = o.PRODUCT_ID
GROUP BY p.PRODUCT_CODE
ORDER BY SALES DESC, p.PRODUCT_CODE ASC;