728x90

48번 이분 그래프


내가 떠올린 풀이 해설

이 문제를 해결하려면 이분 그래프의 대한 이해가 필요하다.

이분 탐색 블로그 : https://hongjw1938.tistory.com/117

 

자료구조 - 이분 그래프(Bipartite Graph)

관련 글 그래프 관련 글은 여기를 참조 그래프 탐색 - BFS는 여기를 참조 그래프 탐색 - DFS는 여기를 참조 1. 이분 그래프 이분 그래프는 그래프 형태의 자료구조인데 정점을 2그룹으로 나눌 수 있

hongjw1938.tistory.com

그래프를 인접 리스트로 구현한다. 모든 노드로 각각 DFS 알고리즘을 적용해 수행한다. DFS를 실행할 때 현재 노드에서 연결된 노드 중 이미 방문한 노드가 나와 같은 집합이면 이분 그래프가 아닌 것으로 판별한다. 실행 결과가 이분 그래프가 아니면 이후 노드는 탐색하지 않는다. DFS를 사용하는 이유는 그래프의 모든 노드가 이어져있지 않고, 여려 개의 부분 그래프로 이뤄진 케이스가 존재할 수 있기 때문이다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek1707 {
	static ArrayList<Integer> list[];
	static int[] check;
	static boolean visit[];
	static boolean IsEven;
	
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n = Integer.parseInt(br.readLine());
		
		for(int i = 0; i < n; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			int v = Integer.parseInt(st.nextToken());
			int e = Integer.parseInt(st.nextToken());
			
			list = new ArrayList[v + 1];
			visit = new boolean[v + 1];
			check = new int[v + 1];
			IsEven = true;
			for(int j = 1; j <= v; j++) {
				list[j] = new ArrayList<>();
			}
			for(int j = 0; j < e; j++) {  // 인접 리스트로 그래프 저장하기 
				st = new StringTokenizer(br.readLine());
				int start = Integer.parseInt(st.nextToken());
				int end = Integer.parseInt(st.nextToken());
				list[start].add(end);
				list[end].add(start);
			}
			// 주어진 그래프가 1개로 연결돼 있다는 보장이 없으므로 모든 노드에서 수행하기 
			for(int j = 1; j <= v; j++) {
				if(IsEven) {
					DFS(j);
				}
				else {
					break;
				}
			}
			check[1] = 0;
			if(IsEven) {
				System.out.println("YES");
			}
			else {
				System.out.println("NO");
			}
		}
	}

	private static void DFS(int node) {
		visit[node] = true;
		for(int i : list[node]) {
			if(!visit[i]) {
				// 인접한 노드는 같은 집합이 아니므로 이전 노드와 다른 집합으로 처리하기 
				check[i] = (check[node] + 1) % 2;
				DFS(i);
			}
			// 이미 방문한 노드가 현재 내 노드와 같은 집합이면 이분 그래프가 아
			else if(check[node] == check[i]){
				IsEven = false;
			}
		}
	}
}

오늘의 회고

오늘은 긴 연휴가 끝나고 시작하는 하루입니다. 연휴동안 잘 쉬고 놀았으니 다시 힘내서 나아가 보겠습니다. 그래프 한 문제를 풀고 주말에 하지 못한 복습을 Do it! 알고리즘 코딩테스트(14번) 까지 진행하였습니다. 

728x90
728x90

백준 16956번 늑대와 양


내가 떠올린 풀이 해설

처음 이 문제를 봤을 때 늑대 기준으로 탐색을 하려고 했다. 문제를 해결하려고 했으나 답이 나오지 않아 블로그를 참고했다. 블로그 풀이는

늑대랑 양이랑 한 칸 떨어져 있으면 울타리로 감싸면 됨, 울타리 갯수 제한 없음, 늑대랑 양이랑 바로 옆만 아니면 양은 무조건 지킬 수 있음을 떠올려서 늑대 주변에 울타리만 감싸주었다. 예제 출력이랑 다르게 나오는데 정답이 나왔다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek16956 {
	static int []dx = {1, 0, -1, 0};
	static int []dy = {0, -1, 0, 1};
	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 m = Integer.parseInt(st.nextToken());
		
		char[][]arr = new char[n][m];
		boolean flag = true;
		
		for(int i = 0; i < n; i++) {
			String tmp = br.readLine();
			for(int j = 0 ; j < m; j++) {
				arr[i][j] = tmp.charAt(j);
			}
		}
		for(int i = 0 ; i < n; i++) {
			for(int j = 0; j < m; j++) {
				if(arr[i][j] == 'W') {
					for(int r = 0; r < 4; r++) {
						int nx = i + dx[r];
						int ny = j + dy[r];
						
						if(nx >= 0 && nx < n && ny >= 0 && ny < m) {
							if(arr[nx][ny] == '.') {
								arr[nx][ny] = 'D';
							}
							else if(arr[nx][ny] ==  'S') {
								flag = false;
								System.out.println(0);
								return;
							}
						}
					}
				}
			}
		}
		if(!flag) {
			System.out.println(0);
		}
		else {
			StringBuilder sb = new StringBuilder();
			System.out.println(1);
			for(int i = 0 ; i < n; i++) {
				sb.append(arr[i]);
				sb.append("\\n");
			}
			System.out.println(sb);
		}
	}
}

백준 1152 단어의 개수


내가 떠올린 풀이 해설

String으로 받아서 StringTokenizer로 공백 기준으로 자르고 StringTokenizer의 개수를 세는 countTokens로 출력해주면 된다.


정확한 풀이

import java.io.*;
import java.util.*;

public class Baek1152 {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		String str = br.readLine();
		
		StringTokenizer st = new StringTokenizer(str);
		System.out.println(st.countTokens());

	}
}

백준 1764번 듣보잡


내가 떠올린 풀이 해설

HashSet을 이용해 N번 까지 HashSet에 넣고 정답을 출력하는 ArrayList을 만들고 br.readLine을 담을 수 있는 String tmp 변수를 만들어서 contains으로 HashSet에 tmp가 있으면 ArrayList에 add 하는 방식으로 풀었다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek1764 {

	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 m = Integer.parseInt(st.nextToken());
		
		HashSet<String> set = new HashSet<>();
		for(int i = 0; i < n; i++) {
			set.add(br.readLine());
		}
		
		ArrayList<String> answer = new ArrayList<>();
		for(int i = 0; i < m; i++) {
			String tmp = br.readLine();
			if(set.contains(tmp)) {
				answer.add(tmp);
			}
		}
		Collections.sort(answer);
		System.out.println(answer.size());
		for(int i = 0; i < answer.size(); i++) {
			System.out.println(answer.get(i));
		}
	}
}

오늘의 회고

오늘은 문자열과 그래프 문제를 풀었습니다. 쉬운 문제들로 풀려고 했는데 늑대와 양 문제에서 막혔습니다. 3주째 알고리즘을 풀고 있는데 꾸준히 문제를 풀고 있어서 진도에서는 만족을 하는데 실력에서는 아직 불만족입니다. 꾸준히 공부하면 실력도 성장할 것이라 믿고 지치지 않고 꾸준히 알고리즘을 풀어나가겠습니다.

 

참고 블로그

https://go-coding.tistory.com/77

728x90
728x90

36번 잃어버린 괄호


내가 떠올린 풀이 해설

가장 작은 최솟값을 만들기 위해서는 가능한 큰 수를 빼야 된다. 수식이 더하기 빼기로만 되어있기 때문에 더하기 부분에 괄호를 쳐서 먼저 모두 계산한 후 빼기를 실행한다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek1541 {
	static int answer = 0;
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		String st = br.readLine();
		String []str = st.split("-");
		
		for(int i = 0; i < str.length; i++) {
			int tmp = mySum(str[i]);
			if(i == 0) {
				answer = answer + tmp;
			}
			else {
				answer = answer - tmp;
			}
		}
		System.out.println(answer);
	}
	private static int mySum(String a) {
		int sum = 0;
		String temp[] = a.split("[+]");
		for(int i = 0; i < temp.length; i++) {
			sum += Integer.parseInt(temp[i]);
		}
		return sum;
	}
}

46번 특정 거리의 도시 찾기


내가 떠올린 풀이 해설

모든 도로 거리가 1이므로 가중치 없는 인접리스트로 표현할 수 있다. 도시의 개수가 300,000, 도로의 최대 크기가 1,000,000이므로 BFS 탐색으로 해결할 수 있다. 최초에는 방문 도시가 1이고, 이동하지 않았으므로 방문 배열에 0을 저장한다. 이후 방문하는 도시는 이전 도시의 방문 배열 값 +1을 방문 배열에 저장한다. 탐색 종료 후 방문 배열에 값이 k와 같은 도시의 번호를 출력한다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek18352 {
	static int [] visit;
	static ArrayList<Integer>[] list;
	static List<Integer> answer;
	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 m = Integer.parseInt(st.nextToken());
		int k = Integer.parseInt(st.nextToken());
		int x = Integer.parseInt(st.nextToken());
		
		list = new ArrayList[n + 1];
		visit = new int[n + 1];
		answer = new ArrayList<>();
		
		for(int i = 1; i <= n; i++) {
			list[i] = new ArrayList<>();
		}
		
		for(int i = 0; i < m; i++) {
			st = new StringTokenizer(br.readLine());
			int s = Integer.parseInt(st.nextToken());
			int e = Integer.parseInt(st.nextToken());
			list[s].add(e);
		}
		for(int i = 1; i <= n; i++) {
			visit[i] = -1;
		}
		BFS(x);
		for(int i = 1; i <= n; i++) {
			if(visit[i] == k) {
				answer.add(i);
			}
		}
		if(answer.isEmpty()) {
			System.out.println(-1);
		}
		else {
			Collections.sort(answer);
			for(int b : answer) {
				System.out.println(b);
			}
		}
	}
	private static void BFS(int x) {
		Queue<Integer> que = new LinkedList<>();
		que.add(x);
		visit[x]++;
		while(!que.isEmpty()) {
			int now = que.poll();
			for(int i : list[now]) {
				if(visit[i] == -1) {
					visit[i] = visit[now] + 1;
					que.add(i);
				}
				
			}
		}
		
	}
}

47번 효율적인 해킹


내가 떠올린 풀이 해설

모든 노드를 각각 BFS 탐색 알고리즘을 적용해 탐색한다. 탐색을 수행하면서 탐색되는 노드들의 신뢰도를 증가시켜 준다. 탐색 종료후 신뢰도 배열을 탐색해 신뢰도의 최댓값을 Max값으로 지정하고, 신뢰도 배열을 다시 탐색하면서 Max값을 가진 노드를 오름차순으로 출력한다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek1325 {
	static int []answer;
	static ArrayList<Integer>[] list;
	static boolean []visit;
	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 m = Integer.parseInt(st.nextToken());
		
		list = new ArrayList[n + 1];
		visit = new boolean[n + 1];
		answer = new int [n + 1];
		for(int i = 1; i <= n; i++) {
			list[i] = new ArrayList<>();
		}
		
		for (int i = 0; i < m; i++) {
			st = new StringTokenizer(br.readLine());
			int s = Integer.parseInt(st.nextToken());
			int e = Integer.parseInt(st.nextToken());
			list[s].add(e);
		}
		for(int i = 1; i <= n; i++) {
			visit = new boolean[n + 1];
			BFS(i);
		}
		int max = 0;
		for(int i = 1; i <= n; i++) {
			max = Math.max(max, answer[i]);
		}
		for(int i = 1; i <= n; i++) {
			if(answer[i] == max) {
				System.out.print(i + " ");
			}
		}
 	}
	private static void BFS(int i) {
		Queue<Integer> que = new LinkedList<>();
		que.add(i);
		visit[i] = true;
		while(!que.isEmpty()) {
			int now = que.poll();
			for(int b : list[now]) {
				if(visit[b] == false) {
					visit[b] = true;
					answer[b]++;
					que.add(b);
				}
			}
 		}
	}
}

잘못된 풀이

import java.io.*;
import java.util.*;
public class Main {
	static int n, m;
	static ArrayList<Integer>[] list;
	static int []answer;
	static boolean []visit;
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		n = Integer.parseInt(st.nextToken());
		m = Integer.parseInt(st.nextToken());
		
		list = new ArrayList[n + 1];
		answer = new int[n + 1];
		for(int i = 1; i <= n; i++) {
			list[i] = new ArrayList<>();
		}
		for(int i = 0; i < m; i++) {
			st = new StringTokenizer(br.readLine());
			int x = Integer.parseInt(st.nextToken());
			int y = Integer.parseInt(st.nextToken());
			list[x].add(y);
		}
		
		for(int i = 1; i <= n; i++) {
			visit = new boolean[n + 1];
			BFS(i);
		}
		int max = 0;
		for(int i = 1; i <= n; i++) {
			max = Math.max(max, answer[i]);
		}
		for(int i = 1; i <= n; i++) {
			if(answer[i] == max) {
				bw.write(i + " ");
			}
		}
		bw.flush();
		bw.close();
	}
	private static void BFS(int i) {
		Queue<Integer> que = new LinkedList<>();
		que.add(i);
		visit[i] = true;
		while(!que.isEmpty()) {
			int now = que.poll();
			for(int b : list[now]) {
				if(visit[b] == false) {
					answer[b]++;
					que.add(b);
				}
				
			}
		}
	}
}


문제점

이 문제에서 진짜 많이 해멧다 계속 시간 초과가 나는 것이었다. 정답이 된 코드와 잘못된 코드와 다른 게 없는데 계속 시간 초과가 났다. 문제를 모르겠다. 뒤에 정답 된 코드를 제출했더니 정답이 나왔다...

 

오늘의 회고

오늘은 그리디와 그래프 문제를 풀어봤습니다. 그래프 문제는 앞에서 배웠던 DFS, BFS를 활용해서 해결하는 문제였다. 앞에서 배웠지만 직접 구현하기에는 힘든 점이 있었습니다. 이번 주말 일요일에는 다른 공부 하지 않고 알고리즘만 복습하는 시간을 가지겠습니다. 알고리즘 공부를 시작한 지 얼마 안 되었기 때문에 지치지 않고 좌절하지 않고 풀어내는 힘을 길어내는 게 중요한 것 같습니다. 요행을 바라지 말고 정직하게 공부하자.

728x90
728x90

32번 동전 0


내가 떠올린 풀이 해설

동전 값이 큰 동전부터 탐색을 하면서 k와 작거나 같은 동전이 나올 때까지 탐색하고 count 값은 k / (동전 값)으로 추가해주고 k % 동전 값으로 k의 값을 바꿔준다. 끝으로 count를 출력한다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek11047 {

	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 k = Integer.parseInt(st.nextToken());
		
		int []arr = new int[n];
		for(int i = 0; i < n; i++) {
			arr[i] = Integer.parseInt(br.readLine());
		}
		int div = 0;
		int cnt = 0;
		int max = 0;
		for(int i = n - 1; i >= 0; i--) {
			if(k >= arr[i]) {
				div = arr[i];
				cnt += k / div;
				k = k % div;
			}
		
		}
		System.out.println(cnt);
	}
}

33번 카드 정렬하기


내가 떠올린 풀이 해설

우선순위 큐를 활용해서 풀어야하는 문제이다. 2개의 값을 합해서 비교해야 한다. 문제의 조건대로 연산을 하면 (10+20) + (30 + 40)이다. 앞의 2개를 더한 값을 바로 사용하므로 더한 값을 큐에 계속 넣어줘야 한다. 그냥 큐를 사용하면 30은 맨 뒤로 들어가 곧바로 연산에 수행될 수 없다. 최소한의 비교를 하기 위해서는 낮은 값부터 먼저 더해야 하므로 오름차순으로 정렬된 상태에서 값을 더하기 위해 우선순위 큐를 사용해야 한다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek1715 {

	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int n = Integer.parseInt(br.readLine());
		PriorityQueue<Integer> pq = new PriorityQueue<>();
		
		for(int i = 0; i < n; i++) {
			int data = Integer.parseInt(br.readLine());
			pq.add(data);
		}
		int data1 = 0;
		int data2 = 0;
		int sum = 0;
		
		while(pq.size() != 1) {
			data1 = pq.remove();
			data2 = pq.remove();
			sum += data1 + data2;
			pq.add(data1 + data2);
		}
		System.out.println(sum);
	}
}

34번 수 묶기


내가 떠올린 풀이 해설

가능한 큰 수들 끼리 묶어야 결괏값이 커진다. 또한 음수끼리 곱하면 양수로 되는 성질을 고려해야 된다. 양수 우선순위 큐와 음수 우선순위 큐와 1의 개수 0의 개수를 카운트하는 변수를 만든다. 데이터를 4개 그룹에 분리해 저장 4개 그룹은 1보다 큰 양수, 1의 개수, 0의 개수, 음수이다. while문을 양수 우선순위 큐 크기가 2보다 작을 때까지 반복하는데 수 2개를 큐에서 뽑고 2 개수를 곱한 값을 결괏값에 더한다.

양수 우선순위 큐에 데이터가 남아있으면 이 데이터를 결과값에 더한다. 음수도 위의 양수와 같이 반복한다 만약 음수 우선순위 큐에 데이터가 남아 있고, 데이터 0이 1개도 없으면 이 데이터를 결과 값에 더한다. 마지막으로 숫자 1의 개수를 결괏값에 더함


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek1744 {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int n = Integer.parseInt(br.readLine());
		PriorityQueue<Integer> plusPq = new PriorityQueue<>(Collections.reverseOrder());
		PriorityQueue<Integer> minusPq = new PriorityQueue<>();
		
		int one = 0;
		int zero = 0;
		
		for(int i = 0; i < n; i++) {
			int data = Integer.parseInt(br.readLine());
			if(data > 1) {
				plusPq.add(data);
			}
			else if(data == 1) {
				one++;
			} 
			else if(data == 0) {
				zero++;
			}
			else {
				minusPq.add(data);
			}
		}
		int sum = 0;
		while(plusPq.size() > 1) {
			int first = plusPq.remove();
			int second = plusPq.remove();
			sum = sum + first * second;
		}
		if(!plusPq.isEmpty()) {
			sum = sum + plusPq.remove();				
		}
		while(minusPq.size() > 1) {
			int first = minusPq.remove();
			int second = minusPq.remove();
			sum = sum + first * second;
		}
		if(!minusPq.isEmpty()) {
			if(zero == 0) {
				sum = sum + minusPq.remove();				
			}
		}
		sum = sum + one;
		System.out.println(sum);
	}
}

35번 회의실 배정


내가 떠올린 풀이

예전에 풀었던 문제와 비슷한 문제여서 어렵지 않게 풀었다. 끝나는 시간으로 정렬을 하고 시작시간으로 정렬을 한다. 끝나는 시간을 기준으로 겹치지 않는 회의실을 선택한다. 


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek1931 {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n = Integer.parseInt(br.readLine());
		ArrayList<Meet> list = new ArrayList<>();
		
		for(int i = 0; i < n; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());	
			int x = Integer.parseInt(st.nextToken());
			int y = Integer.parseInt(st.nextToken());
			list.add(new Meet(x, y));
		}
		int cnt = 0;
		Collections.sort(list);
		int et = 0;
		for(Meet b : list) {
			if(b.x > et) {
				cnt++;
				et = b.y;
			}
		}
		System.out.println(cnt);
	}
}
class Meet implements Comparable<Meet> {
	int x;
	int y;
	Meet(int x, int y) {
		this.x = x;
		this.y = y;
	}
	@Override
	public int compareTo(Meet o) {
		if(this.x == o.x) {
			return this.y - o.y;
		}
		return this.x - o.x;
	}
}

오늘의 회고

오늘은 그리디 알고리즘에 배워보는 시간이였습니다. 오늘 문제들도 쉽지 않은 문제들로 구성이 돼있어 힘들었습니다. 알고리즘을 풀면서 고민해도 답을 못 풀 경우에 답을 보고 다시 풀어야 되나 아니면 계속 고민해야 되나 라는 고민이 생기는데 계속 고민해 보는 것이 가장 좋은 방법이라고 생각하는데 저는 시간의 제약 때문에 답을 보고 다시 풀고 복습하고 공부하는 식으로 내 것으로 만들고 있습니다. 아직 풀 수 있는 문제가 많진 않지만 계속해서 공부하겠습니다.

728x90
728x90

백준 2417번 정수 제곱근


내가 떠올린 풀이 해설

처음 이 문제를 봤을 때 이분 탐색 문제라는 것을 떠올리지 못했다. 최솟값을 구하기 위해 min에다 long의 최댓값을 선언하고 start를 0 end를 입력 숫자 n으로 잡고 mid를 (start + end) / 2로 정해준다. value라는 변수를 하나 더 만들어 Math.pow(mid, 2) pow 메소드는 제곱근을 구할 수 있는 메소드이다. 제곱근이 0보다 커야 되니 if(value > 0)에서 if(value >= n) 일 때 최솟값 min = Math(min, mid)로 최솟값으로 바꿔준다.  if(value >= n) 일 때 end 값을 mid - 1 value가 n 보다 작으면 start 값을 mid + 1로 바꿔준다. while문 밖에서 min의 값을 출력해준다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek2417 {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		long n = Long.parseLong(br.readLine());
		long start = 0;
		long end = n;
		long min = Long.MAX_VALUE;
		while(start <= end) {
			long mid = (start + end) / 2;
			long value = (long)Math.pow(mid, 2);
			if(value >= 0) {
				if(value >= n) {
					min = Math.min(min, mid);
					end = mid - 1;
				}
				else {
					start = mid + 1;
				}
			}
		}
		System.out.println(min);
	}
}

백준 10815번 숫자 카드


내가 떠올린 풀이 해설

어제 풀었던 29번 수 찾기 문제와 비슷한 접근을 하면 풀리는 문제입니다. 기본 이분 탐색 문제입니다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek10815 {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n = Integer.parseInt(br.readLine());
		int [] arr = new int[n];
		StringTokenizer st = new StringTokenizer(br.readLine());
		for(int i = 0; i < n; i++) {
			arr[i] = Integer.parseInt(st.nextToken());
		}
		Arrays.sort(arr);
		int m = Integer.parseInt(br.readLine());
		st = new StringTokenizer(br.readLine());
		for(int i = 0; i < m; i++) {
			int look = Integer.parseInt(st.nextToken());
			int start = 0;
			int end = arr.length - 1;
			boolean result = false;
			while(start <= end) {
				int mid = (start + end) / 2;
				int midV = arr[mid];
				if(midV < look) {
					start = mid + 1;
				}
				else if(midV > look){
					end = mid - 1;
				}
				else {
					result = true;
					break;
				}
			}
			if(result) {
				System.out.print(1 + " ");
			}
			else {
				System.out.print(0 + " ");
			}
		}	
	}
}

백준 2805번 나무 자르기


내가 떠올린 풀이 해설

이 문제는 이분 탐색 문제인데 언제 이분 탐색을 사용하는지 못 떠올리다가 문제를 풀면서 떠올리게 되었습니다. arr배열에 넣으면서 end값을 최댓값으로 구한다. while(start < end) sum 변수를 만들고 mid 값을 (start + end) / 2 넣어준다. for문을 배열만큼 탐색하면서 arr [i] - mid값이 0보다 클 때 sum에 계속 더해준다. for문 밖에서 만약 sum이 m 보다 작으면 end에 mid를 넣어주고 작지 않으면 start에 mid + 1을 넣어주고 while문 밖에서 start - 1을 출력해준다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek2805 {

	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 m = Integer.parseInt(st.nextToken());
		
		int []arr = new int[n];
		int start = 0;
		int end = 0;
		st = new StringTokenizer(br.readLine());
		for(int i = 0; i < n; i++) {
			arr[i] = Integer.parseInt(st.nextToken());
			if(end < arr[i]) {
				end = arr[i];
			}
		}
		while(start < end) {
			long sum = 0;
			int mid = (start + end) / 2;
			for(int i = 0; i < n; i++) {
				if(arr[i] - mid > 0) {
					sum += arr[i] - mid;
				}
			}
			if(sum < m) {
				end = mid;
			}
			else{
				start = mid + 1;
			}
		}
		System.out.println(start - 1);
	}
}

오늘의 회고

오늘은 이분 탐색 기본 문제를 풀었습니다. 이분 탐색을 공부하면서 젤 어려운 점이 이분 탐색을 언제 적용해야 되는지 떠올리는데 어려움이 있었습니다. 아직까지 많이 부족하다고 생각하고 알고리즘을 풀면서 계속 복습하고 새로운 문제를 풀겠습니다. 하루하루 열심히 꾸준히 노력하겠습니다.

728x90
728x90

29번 수 찾기


내가 떠올린 풀이 해설

N의 최대 범위가 100,000이므로 단순 반복문으로는 풀 수가 없다. 이진 탐색을 적용하면 logn의 시간 복잡도를 사용하므로 이진 탐색을 이용해서 풀어야 된다. 이진 탐색은 정렬이 된 상태여야 하므로 정렬을 하고 start = 0 end = arr.length - 1로 기준을 잡는다. midV에 중앙값을 넣는다. 만약 midV가 크면 end의 값을 mid - 1로 바꿔준다. 작으면 start값을 mid + 1의 값으로 바꿔준다. 같으면 find를 true로 넣어준 후 break로 빠져나온다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek1920 {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int n = Integer.parseInt(br.readLine());
		int []arr = new int[n]; 
		StringTokenizer st = new StringTokenizer(br.readLine());
		for(int i = 0; i < n; i++) {
			arr[i] = Integer.parseInt(st.nextToken());
		}
		Arrays.sort(arr);
		int m = Integer.parseInt(br.readLine());
		st = new StringTokenizer(br.readLine());
		
		for(int i = 0; i < m; i++) {
			int target = Integer.parseInt(st.nextToken());
			boolean result = false;
			int start = 0;
			int end = arr.length - 1;
			while(start <= end) {
				int mid = (start + end) / 2;
				int midV = arr[mid];
				if(midV > target) {
					end = mid - 1;
				}
				else if(midV < target) {
					start = mid + 1;
				}
				else {
					result = true;
					break;
				}
			}
			if(result) {
				System.out.println(1);
			}
			else {
				System.out.println(0);
			}
		}
	}
}

30번 문제 기타 레슨


내가 떠올린 풀이 해설

문제를 이해하는데 시간이 걸렸다. 블루레이 크기가 모두 같고 녹화 순서가 바뀌지 않아야 함이라는 조건에서 이진 탐색을 사용해야된다는 단서이다. 첫 레슨부터 마지막까지 차례대로 저장하다 보면 지정한 크기로 모든 레슨을 저장할 수 있는지 판단할 수 있기 때문이다.

모두 저장할 수 있으면 크기를 줄이고 저장할 수 없다면 크키를 늘려주는 방식으로 크기의 최솟값을 알 수 있다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek2343 {

	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 m = Integer.parseInt(st.nextToken());
		
		int []arr = new int[n];
		int start = 0;
		int end = 0;
		st = new StringTokenizer(br.readLine());
		for(int i = 0; i < n; i++) {
			arr[i] = Integer.parseInt(st.nextToken());
			if(start < arr[i]) {
				start = arr[i];  // 레슨 최댓값을 시작 인덱스로 저장하기
			}
			end = end + arr[i]; // 모든 래슨의 총합을 종료 인덱스로 저장하기
		}
		while(start <= end) {
			int mid = (start + end) / 2;
			int sum = 0;
			int count = 0;
			for(int i = 0; i < n; i++) {  // mid 값으로 모든 레슨을 저장할 수 있는지 확인
				if(sum + arr[i] > mid) {
					count++;
					sum = 0;
				}
				sum = sum + arr[i];
			}
			if(sum != 0) {  // 탐색후 sum이 0이 아니면 블루레이가 1개 더 필요하므로 더함
				count++;
			}
			if(count > m) {
				start = mid + 1;
			}
			else {
				end = mid - 1;
			}
		}
		System.out.println(start);
	}
}

 


31번 문제 K번째 수


책 풀이 해설

k의 범위가 1 ~ min(10^9, N^2)이므로 시간 복잡도가 N^2인 알고리즘은 사용할 수 없다. 이진 탐색으로 중앙값보다 작은 수의 개수를 세면서 범위를 절반씩 줄이는 방법으로 B [k] 값을 구한다. 작은 수의 개수가 k - 1 개인 중앙값이 정답이다.


정확한 풀이

import java.util.*;
public class Baek1300 {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int m = sc.nextInt();
		
		long start = 1;
		long end = m;
		long answer = 0;
		
		while(start <= end) {
			long mid = (start + end) / 2;
			long cnt = 0;
			
			for(int i = 1; i <= n; i++) {
				cnt += Math.min(mid / i, n);
			}
			if(cnt < m) {
				start = mid + 1;
			}
			else {
				answer = mid;
				end = mid - 1;
			}
		}
		System.out.println(answer);
	}
}

문제점

이진탐색을 떠올리기 힘들었고 중앙값보다 작은 수의 개수를 세면서 줄이는 방법을 이용해서 작은 수의 개수가 k -1 개인 중앙값이 정답이라는 아이디어를 못 떠올렸다.


백준 11866번 요세푸스 문제 0

내가 떠올린 풀이 해설

기본 큐를 이용해서 푸는 문제이다. 큐가 비어 있을 때까지 반복한다. 큐를 pop 하고 다시 그 수를 push 해서 k번째 pop을 할 때 String str에 더해준다. 


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek11866 {

	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 m = Integer.parseInt(st.nextToken());
		
		Queue<Integer> que = new LinkedList<>();
		
		for(int i = 1; i <= n; i++) {
			que.offer(i);
		}
		int cnt = 0;
		String str = "<";
		while(!que.isEmpty()) {
			cnt++;
			if(cnt == m) {
				str += que.poll() + ", ";
				cnt = 0;
			}
			else {
				que.offer(que.poll());
			}
		}
		str = str.substring(0, str.length() - 2);
		System.out.print(str + ">");
	}
}

오늘의 회고

오늘은 이진탐색 문제를 풀었습니다. 이진 탐색을 사용하는 문제에서 이진 탐색을 사용해야 되는 아이디어를 떠올리기 힘들었습니다. 마지막 문제는 어려워서 풀지 못했습니다. 이진 탐색에 대해 공부하기 위해 내일은 이진 탐색 중에 난의도가 높지 않은 문제를 풀겠습니다.

 

728x90
728x90

백준 10814번 나이순 정렬


내가 떠올린 풀이 해설

정렬 문제이다. Arrays.sort()를 사용해서 정렬을 한다. 또한 Comparator를 이용한다. o1은 첫 번째 행이고 arr [0][0]이다.  o2는 두 번째 행이고 arr [1][0]이다. o1[0] - o2[0] 정렬해준다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek10814 {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int n = Integer.parseInt(br.readLine());
		String [][] arr = new String[n][2];
		
		for(int i = 0; i < n; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			arr[i][0] = st.nextToken();
			arr[i][1] = st.nextToken();
		}
		Arrays.sort(arr, new Comparator<String[]>() {

			@Override
			public int compare(String[] o1, String[] o2) {
				return Integer.parseInt(o1[0]) - Integer.parseInt(o2[0]);
			}
			
		});
		for(int i = 0; i < n; i++) {
			System.out.println(arr[i][0]);
			System.out.println(arr[i][1]);
		}
	}
}

백준 11650번 좌표 정렬하기


내가 떠올린 풀이 해설

기본 정렬 문제이다. Point 클래스를 만들어서 Comparable를 이용해서 정렬을 진행했다. this.x 와 o.x가 같으면 y값으로 비교했다.

import java.io.*;
import java.util.*;
public class Baek11650 {

	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int n = Integer.parseInt(br.readLine());
		ArrayList<Point> arr = new ArrayList<>();
		
		for(int i = 0; i < n; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			int x = Integer.parseInt(st.nextToken());
			int y = Integer.parseInt(st.nextToken());
			arr.add(new Point(x, y));
		}
		Collections.sort(arr);
		for(Point o : arr) {
			System.out.println(o.x + " " + o.y);
		}
	}
}
class Point implements Comparable<Point> {
	int x;
	int y;
	Point(int x, int y) {
		this.x = x;
		this.y = y;
	}
	@Override
	public int compareTo(Point o) {
		if(this.x == o.x) {
			return this.y - o.y;
		}
		else {
			return this.x - o.x;
		}
	}
}

오늘의 회고

복습을 끝내고 시간이 남아서 정렬 문제 2문제를 풀었습니다. 기본적인 정렬 문제라 시간이 많이 걸리지는 않았습니다. 아직 배워야 하는 알고리즘들이 많은데 너무 성급하게 넘어가지 말고 정석대로 공부하자.

728x90
728x90

26번 DFS와 BFS


내가 떠올린 풀이 해설

DFS와 BFS를 구현할 수 있는지 물어보는 기본 문제이다.

문제 조건에서 작은 번호의 노드부터 탐색한다고 했으므로 인접 노드를 오름차순으로 정렬한 후 구현한다. 또한 DFS가 끝났을 떼 방문 배열을 초기화해준다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek1260 {
	static ArrayList<Integer> arr[];
	static boolean visited[];
	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 m = Integer.parseInt(st.nextToken());
		int v = Integer.parseInt(st.nextToken());
		
		arr = new ArrayList[n + 1];
		for(int i = 1; i <= n; i++) {
			arr[i] = new ArrayList<>();
		}
		
		for(int i = 0; i < m; i++) {
			st = new StringTokenizer(br.readLine());
			int e = Integer.parseInt(st.nextToken());
			int s = Integer.parseInt(st.nextToken());
			arr[e].add(s);
			arr[s].add(e);
		}
		for(int i = 1; i <= n; i++) {
			Collections.sort(arr[i]);
		}
		visited = new boolean[n + 1];
		DFS(v);
		System.out.println();
		visited = new boolean[n + 1];
		BFS(v);
	}
	private static void BFS(int i) {
		Queue<Integer> que = new LinkedList<>();
		que.add(i);
		visited[i] = true;
		
		while(!que.isEmpty()) {
			int now = que.poll();
			System.out.print(now + " ");
			for(int b : arr[now]) {
				if(!visited[b]) {
					visited[b] = true;
					que.add(b);
				}
			}
		}
	}
	private static void DFS(int i) {
		System.out.print(i + " ");
		visited[i] = true;
		for(int b : arr[i]) {
			if(!visited[b]) {
				DFS(b);
			}
		}
	}
}

27번 미로 탐색


내가 떠올린 풀이 해설

N, M의 최대 크기가 100으로 매우 작기 때문에 DFS나 BFS의 시간제한은 생각하지 않아도 되는 문제다.

지나야 하는 칸수의 최솟값을 구하는 문제이므로 BFS로 풀었다. 상하좌우를 탐색하면서 칸의 숫자가 1이면서 아직 방문하지 않았다면 큐에 삽입한다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek2178 {
	static int arr[][];
	static boolean visited[][];
	static int []dx = {1, 0, -1, 0};
	static int []dy = {0, 1, 0, -1};
	static int n,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());
		m = Integer.parseInt(st.nextToken());
		
		arr = new int[n][m];
		visited = new boolean[n][m];
		
		for(int i = 0; i < n; i++) {
			st = new StringTokenizer(br.readLine());
			String line = st.nextToken();
			for(int j = 0; j < m; j++) {
				arr[i][j] = Integer.parseInt(line.substring(j, j + 1));
			}
		}
		BFS(0,0);
		System.out.println(arr[n - 1][m - 1]);
	}

	private static void BFS(int i, int j) {
		Queue<int[]> que = new LinkedList<>();
		que.offer(new int[]{i, j});
		visited[i][j] = true;
		while(!que.isEmpty()) {
			int now[] = que.poll();
			
			for(int k = 0; k < 4; k++) {
				int x = now[0] + dx[k];
				int y = now[1] + dy[k];
				if(x >= 0 && x < n && y >= 0 && y < m) {
					if(arr[x][y] != 0 && !visited[x][y]) {
						visited[x][y] = true;
						arr[x][y] = arr[now[0]][now[1]] + 1;
						que.add(new int[] {x,y});
					}
				}
			}
		}
	}
}

문제점

자연스럽게 Integer.parseInt(st.nextToken())으로 코드를 작성했는데 오류가 발생했다. 왜 오류가 났는지 찾다가 입력 예제가 띄어쓰기로 되어있는 게 아니라 한 줄로 붙어었다는것을 발견했다... que.add 할 때 {x, y}를 add 해야 되는데 {i, j}를 add를 해서 계속 답이 안 나왔다. 이번 문제 오류를 찾느라 한참 걸렸다.


28번 문제 트리의 지름


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek1167 {
	static boolean visited[];
	static int[] distance;
	static ArrayList<Edge> []arr;
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n = Integer.parseInt(br.readLine());
		
		arr = new ArrayList[n + 1];
		for(int i = 1; i <= n; i++) {
			arr[i] = new ArrayList<Edge>();
		}
		for(int i = 0; i < n; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			int s = Integer.parseInt(st.nextToken());
			while(true) {
				int e = Integer.parseInt(st.nextToken());
				if(e == -1) {
					break;
				}
				int v = Integer.parseInt(st.nextToken());
				arr[s].add(new Edge(e, v));
			}
		}
		distance = new int[n + 1];
		visited = new boolean[n + 1];
		BFS(1);
		int max = 1;
		for(int i = 2; i <= n; i++) {
			if(distance[max] < distance[i]) {
				max = i;
			}
		}
		distance = new int[n + 1];
		visited = new boolean[n + 1];
		BFS(max);
		Arrays.sort(distance);
		System.out.println(distance[n]);
	}
	private static void BFS(int index) {
		Queue<Integer> que = new LinkedList<>();
		que.add(index);
		visited[index] = true;
		while(!que.isEmpty()) {
			int now = que.poll();
			for(Edge i : arr[now]) {
				int e = i.e;
				int v = i.value;
				if(!visited[e]) {
					visited[e] = true;
					que.add(e);
					distance[e] = distance[now] + v;
				}
			}
		}	
	}
}
class Edge {
	int e;
	int value;
	public Edge(int e, int value) {
		this.e = e;
		this.value = value;
	}
}

문제점

문제를 고민해봤지만 풀지 못했다. 아직 골드까지 풀기는 부족한 실력인 것 같다.

 

오늘의 회고

오늘은 책에 있는 문제를 풀었습니다. 책이 실전 대비 책이라 그런지 어려운 문제들이 포함되어있습니다.ㅠㅠ  안 풀린다고 좌절하지 말고 천천히 기본부터 익혀 나가겠습니다. 내일은 그동안 학습했던 문제들 복습하고 정리하는 시간과 시간이 되면 오늘 보단 쉬운 문제를 풀겠습니다.

728x90

'알고리즘 > 알고리즘 문제풀이' 카테고리의 다른 글

백준) 스택, 문자열  (0) 2022.05.30
백준)정렬  (0) 2022.05.27
백준)DFS  (0) 2022.05.25
Do it! 알고리즘 코딩 테스트 (22번 ~ 25번)  (0) 2022.05.24
Do it! 알고리즘 코딩테스트(16번 ~ 20번)  (0) 2022.05.23

+ Recent posts