https://www.acmicpc.net/problem/1958

 

1958번: LCS 3

첫 줄에는 첫 번째 문자열이, 둘째 줄에는 두 번째 문자열이, 셋째 줄에는 세 번째 문자열이 주어진다. 각 문자열은 알파벳 소문자로 이루어져 있고, 길이는 100보다 작거나 같다.

www.acmicpc.net

 

계속 이어서 LCS의 세 번째 문제입니다.

LCS를 충분히 이해했다면 쉽게 접근이 가능합니다.

 

 

최소공배수처럼 접근해서 두 문자열의 LCS를 먼저 구하고, 구한 문자열과 비교하면 구현이... 틀립니다!

 

예외가 존재하기 때문인데, 쉽게 생각해 낼 수 있는 예외는 

처음 구한 LCS와 길이가 같은 다른 문자열이 존재하는 경우도 있을 것 같고, 3개 문자열의 LCS가 두 문자열의 LCS와 다른 문자를 갖는 경우도 있을 것 같네요.

 

AAAAAAAD

ADAAAAA

AD

3개의 문자열이 있을 때 세 문자열의 LCS는 AD가 되겠지만 1번과 2번 문자열의 LCS는 AAAAAA가 되어 두 문자열의 LCS를 먼저 구할 경우 오답이 나오게 됩니다.

 

그럼 어떻게 구현해야할까요?

LCS를 구하던 방법과 똑같이 하되, 문자열이 세 개가 되었으니 3차원 배열로 확장해서 구현하면 됩니다.

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		char[] str1 = br.readLine().toCharArray();
		int l1 = str1.length;
		char[] str2 = br.readLine().toCharArray();
		int l2 = str2.length;
		char[] str3 = br.readLine().toCharArray();
		int l3 = str3.length;

		int[][][] dp = new int[l3 + 1][l2 + 1][l1 + 1];

		for (int i = 1; i <= l3; i++) {
			char c3 = str3[i - 1];
			
			for (int j = 1; j <= l2; j++) {
				char c2 = str2[j - 1];
				
				for (int k = 1; k <= l1; k++) {
					if (c3 == c2 && c2 == str1[k - 1]) {
						dp[i][j][k] = dp[i - 1][j - 1][k - 1] + 1;
					} else {
						dp[i][j][k] = Math.max(dp[i][j][k - 1], Math.max(dp[i - 1][j][k], dp[i][j - 1][k]));
					}
				}
			}
		}
		System.out.println(dp[l3][l2][l1]);
	}
}

 

바로 이렇게요.

감사합니다!

 

(String의 순서를 거꾸로 비교한 건 LCS 1번, 2번에서 사용한 코드를 수정해서 작성했기 때문입니다! index만 맞는다면 어떤 식으로 반복문을 작성해도 상관없습니다.)

728x90

https://www.acmicpc.net/problem/9252

 

9252번: LCS 2

LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.

www.acmicpc.net

 

LCS 2번을 풀어보겠습니다.

혹시 LCS에 대한 이해가 부족하시거나, LCS 1번 문제를 아직 풀지 않은 분은

https://nodingco.tistory.com/9

 

[JAVA] 백준 9251번. LCS (골드5)

https://www.acmicpc.net/problem/9251 9251번: LCS LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들..

nodingco.tistory.com

이 글을 확인해주시면 감사하겠습니다.

 

문제는 LCS 1번과 아주 유사합니다. 하지만 단순히 LCS의 길이를 구하는 것 뿐 아니라 LCS의 내용까지 구해야합니다.

쉽게 생각하면 그저 LCS를 구하는 기존의 과정에 더해 여태까지의 String을 저장해도 될 것 같지만, String이 메모리나 연산시간을 많이 잡아먹는걸 감안하면 살짝 위험해 보입니다.

그래서 LCS를 구했던 과정을 역산해서 LCS를 알아내 보겠습니다.

 

예제의 풀이과정이 기록되는 DP 배열을 실제 표로 나타내어 봅시다. (실제로는 계산의 편의를 위해 좌측과 상단에 0이 들어간 배열이 더 존재합니다.)

 

  A C A Y K P
C 0 1 1 1 1 1
CA 1 1 2 2 2 2
CAP +1 1 2 2 2 3
CAPC 1 +2 2 2 2 3
CAPCA 1 2 +3 3 3 3
CAPCAK 1 2 3 3 +4 4

정답 LCS인 ACAK는 위와같은 과정을 통해 구해졌다는걸 알 수 있고

최종 정답이 위치한 DP[L2][L1]의 값부터 역순으로 찾아 가는 방법도 알 수 있습니다.

 

위, 좌측, 대각선 좌상방향 세개의 값을 비교하여

나와 같은 값이 있으면 그 쪽으로, 나와 값이 전부 다를땐 좌상방향으로 이동하면서

그때의 Character를 역순으로 담으면 자연스럽게 답이 찾아집니다.

Stack을 이용해 역순으로 저장하는 방법을 구현하면, 코드는 아래와 같아집니다.

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;

public class Main {

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();
		Stack<Character> stack = new Stack<Character>();

		char[] str1 = br.readLine().toCharArray();
		int l1 = str1.length;
		char[] str2 = br.readLine().toCharArray();
		int l2 = str2.length;

		int[][] dp = new int[l2 + 1][l1 + 1];

		for (int i = 1; i <= l2; i++) {
			char C = str2[i - 1];
			for (int j = 1; j <= l1; j++) {
				if (C == str1[j - 1]) {
					dp[i][j] = dp[i - 1][j - 1] + 1;
				} else {
					dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);
				}
			}
		}
		sb.append(dp[l2][l1]).append("\n");

		int now = dp[l2][l1];
		int x = l2;
		int y = l1;

		while (isIn(x, y) && now > 0) {
			if (dp[x - 1][y] == now) {
				x--;
			} else if (dp[x][y - 1] == now) {
				y--;
			} else {
				x--;
				y--;
				now--;
				stack.push(str1[y]);
			}

		}

		while (!stack.isEmpty()) {
			sb.append(stack.pop());
		}

		System.out.println(sb);
	}

	static boolean isIn(int x, int y) {
		if (0 < x && 0 < y) {
			return true;
		}
		return false;
	}
}

 

주의)

LCS가 0일때 아무것도 출력하지 않아야합니다.

탐색 도중 x와 y가 ArrayIndex를 벗어나는걸 주의해주세요.

728x90

https://www.acmicpc.net/problem/9251

 

9251번: LCS

LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.

www.acmicpc.net

 

안녕하세요!

오늘부터 LCS(최장 공통부분 수열) 문제 3개를 연속으로 풀어보겠습니다!

부분 수열 문제지만 오늘 가져온 9251번 문제처럼 String을 찾는 유형으로도 나오는데요,

0-1 배낭 문제 (Knapsack Problem)과 더불어서 DP의 대표 유형 격인 문제입니다.

그럼 천천히 풀어보겠습니다.

 

 

 

예제를 기준으로 함께 풀어보겠습니다. 

DP의 풀이방법은 정말 다양하고, Dynamic Programming이란 말 그대로 모든 게 가능하기 때문에 딱 잡아 말할 순 없지만, 분할 정복과 유사하게 문제를 잘게 쪼개어 그 결과를 기억하고 이를 통해 답을 만들어낸다고 볼 수 있습니다.

LCS문제도 같습니다.

 

ACAYKP를 String1이라고 하고 이걸 기준으로 놓고 아래의 CAPCAK, String2 의 부분수열을 만들어서 비교해보면,

 

1. C 일때

A-> 0

AC -> 1

ACA-> 1

ACAY ->1

ACAYK ->1

ACAYKP ->1

String2가 C라고 가정했을 때 만들 수 있는 LCS는 길이가 1이라는 사실을 알 수 있습니다.

 

2. CA 일 때

A->1

AC -> 1   (A도 가능하지만 가독성과 이해를 위해 C를 bold 처리했습니다.)

ACA -> 2

ACAY ->2

ACAYK ->2

ACAYKP ->2 String2가 CA일때 만들 수 있는 LCS는 2의 길이라는 사실을 알 수 있습니다.

 

3. CAP 일때

A-> 1

AC -> 1

ACA-> 2

ACAY ->2

ACAYK ->2

ACAYKP ->3

두번째 String이 CAP일 때 LCS는 길이가 3입니다.

슬슬 규칙이 보이시나요? 비교하는 String이 길어질 때,

LCS의 값은 이전에 이 길이까지와 비교한 값과 같거나, 이번에 비교하면서 만들어진 현재의 LCS값이거나,

String1의 이번 Character와 String2에 방금 더해진 문자가 같을 때 1이 커집니다.

 

이걸 코드로 표현해 보면

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;


public class Main{
	
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		String str1 = br.readLine();
		int l1 = str1.length();
		String str2 = br.readLine();
		int l2 = str2.length();
		
		int[][] dp = new int[l2+1][l1+1];
		
		for(int i = 1; i <= l2; i++) {
			char C = str2.charAt(i-1);
			for(int j = 1; j <= l1; j++) {
				if(C == str1.charAt(j-1)) {
					dp[i][j] = dp[i-1][j-1] + 1;
				}else {
					dp[i][j] = Math.max(dp[i][j-1], dp[i-1][j]);
				}
			}
		}
		System.out.println(dp[l2][l1]);
	}
}

이렇게 나타낼 수 있을것 같네요.

위에서 설명한 것과 같이 String2의 길이를 1씩 늘려가면서 String1과 비교해주고

이번에 비교하는 문자가 같다면 LCS의 값은 이전 비교에서 1만큼 짧았을때의 최댓값 + 1

다르다면 이전 비교에서의 값과 이번 비교에서의 값 중에 큰 값으로 결정됩니다.

 

대부분의 DP문제는 아이디어를 끌어내기가 어렵지, 풀이 방법만 안다면 구현은 쉬운 경우가 많습니다.

DP를 잘 풀기 위해서는 역시 여러 유형을 경험해 익숙해지고 직접 그려가면서 규칙을 찾아내는 방법 뿐 입니다.

이어서 거의 비슷한 문제인 LCS2도 풀어보겠습니다.

728x90

아직 한 달이 더 남아있긴 하지만,

싸피5기의 공식적인 일정이 거의 끝났다!

 

6기와 7기는 천명 안팎의 많은 수강생을 모집한다는데,

개발자를 꿈꾸는 많은 사람들이 기회를 얻었으면 좋겠다.

 

11개월의 시간동안 정말 많이 변한것 같다.

 

발전한 부분 : 

Web관련 지식이 없었는데 나름 능숙한 개발자가 되었다. 

변명이지만 모교의 웹 수업이 조금... 꺼려지는 요소가 있어서 듣지 않았다.

덕분에 웹 관련해선 아무것도 모르는 까막눈이었는데 싸피 과정을 통해 FE던 BE던 개발할 역량이 생겼다.

 

알고리즘 관련 지식이 대폭 성장했다. 

알고리즘 수업은 들었지만, 백준의 존재를 알면서도 외면해왔던 내가 1년도 되지 않는 시간동안 500문제를 넘게 풀었다!

공부를 하면서 스스로 내 실력이 늘어나는게 느껴졌다.

몇 달 전만 해도 실버 난이도에도 덜컥 걸리는 나였는데 이젠 골드 5단계쯤은 눈 감고도 푼다. (거짓말입니다. ㅎㅎ)

코딩테스트도 어지간하면 통과하는 수준이 되었다.

 

개발자로서의 체력이 생겼다.

상반기 내내 하루 8시간의 수업을 듣고 하반기엔 7주 단위로 이어지는 프로젝트들을 강도 높게 진행했다.

학부 과정에서도 공부량이 많았지만 이론,암기 내용이 많았다면 진짜 개발로 꽉꽉 채워진 하루를 보낸것 같다.

다녀본 적은 없지만 회사에 출근해서도 자연스럽게 가능할것 같은 자신감! 생겼다.

 

좋은 인연이 생겼다.

상반기를 같이 보낸 12반 사람들, 하반기 팀플로 만난 사람들... 

같이 얘기할 수 있고 지식을 나눌 수 있는 같은 지인들이 생겼다는건 참 든든한것 같다.

 

더 노력할 부분 : 

중간 중간 마음이 흔들렸던 시간들

정말, 정말 솔직히 말해서 하루 24시간 잠자는 6시간을 빼고 기본적으로 식사나 세면을 하는 시간을 빼고,

내가 진짜 집중한 시간이 얼마나 될까 생각해보면... 많이 부족한것 같다.

물론 적절한 휴식과 스트레스 해소도 필요하겠지만 '코딩의 재미'를 안다고 자부하는 입장에서 쓸데없이 흘려보낸 시간이 많은것도 부정할 수 없다. 

나에게 채찍을 들어야 될 시간이다.... 

 

아직 소화하지 못한 많은 지식들

많은걸 배웠고, 잊어버렸고, 배워야 한다는 사실을 알았다.

수업 과정중에도 정리까지 하는 분들이 있던데 나는 뒤늦게나마 정리와 기록을 하면서 복습해보려고 한다.

 

 

불어난 뱃살

11개월동안 살이 정말 많이 쪘다...

2020년에 코로나로 4학년이 널널하던 틈을 타서 운동을 많이 했는데 다 도루묵이 되었다.

재택수업으로 인해 활동량이 0에 가까운데 머리를 쥐어짜내다 보면 달달한게 땡기고...

10시,11시까지 코딩을 하고나면 지쳐서 운동은 커녕 바로 눕게 된다.

이제 힘든 시간들은 거의 끝났으니 앞으로는 몸도 신경쓰면서! 공부해야겠다.

 

 

 

이런 사람들에게 싸피를 추천한다.

 

1. 개발자를 꿈꾸는 비전공자

 

싸피 과정중에, 비전공자분들을 만날 일이 꽤 있었다.

같은 팀원으로도 경쟁하는 옆 팀으로도.

다들 전공자 못지 않은 실력을 가졌고 다른 전공분야에서 오는 창의성이나 경쟁성이 느껴졌다.

요즘 속칭 '네카라쿠배'에 가겠다며 수백만원을 내야하는 학원들도 생겼다는데

웹 분야에만 한정짓지 않고 개발자를 꿈꾸는 모든 비전공자에게 싸피는 최고의 선택이 아닐까 싶다.

 

2. 앞으로 어떤 길을 택해야할지 생각이 많은 전공자

 

내 경우였다.

4년동안 학부과정을 들으며... 어느정도 지식은 쌓았다고 생각했지만

내 지식을 실무에서 어떻게 사용해야하는지 어떤 준비가 필요하고 부족한지 안개가 자욱한 길을 걷는 기분이었다.

싸피 과정중에 여러 프로젝트를 진행하고, 특화된 기술을 습득하고, IT이슈와 트렌드에 대해 배우면서 안개가 좀 걷힌 듯 하다. 웹 프로그래밍 관련해서 아예 모르던 내가 어느정도 흉내를 낼 수 있게 되었고... 

 

3. 학부과정에서 배운 내용을 정리할 시간이 필요한 전공자

 

지금의 내 모습인것 같다.

1학년을 제외하고 3년, 무시무시하게 많은 전공과목의 지식을 우리는 겉핥기로만 배웠다.

그 내용들을 정리하고 소화해서 내 것으로 만들 시간이 필요한데,

싸피를 수강하는 동안은 경제적인 문제에서도 벗어날 수 있고 개발의 감도 잃지 않으면서 시간이 충분히 주어진다.

나도 싸피 과정동안 배운 내용들을 잘 정리해서 내 것으로 만들어야겠다!

 

 

싸피 5기 여러분 전부 수고 많으셨습니다!

좋은 곳에서 좋은 모습으로 다시 뵙기를.... 이라고 말하기엔 코로나때문에 한번도 못봤잖아!! 🤣 

728x90

알고리즘 풀이 포스팅을 작성하다 보니! 

JAVA 언어에 입출력 방법이 많아서 처음 PS를 접하시는 분들이 헷갈릴 법도 하다!라는 생각이 들었습니다.

그래서 JAVA에서 주로 사용되는 입출력 방법들을 총 정리해보도록 하겠습니다!

 

입력


1. Scanner

import java.util.Scanner;
//util 패키지에서 Scanner import

public class io_test {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		// Scanner 선언

		int i = sc.nextInt();
		// Integer 타입 받아오기

		long l = sc.nextLong();
		// Long 타입 받아오기 (JAVA의 Long은 C의 LongLong과 같은 크기입니다.)

		double d = sc.nextDouble();
		// Double 타입 받아오기

		float f = sc.nextFloat();
		// Float 타입 받아오기

		String str1 = sc.next();
		//String으로 입력 받아오기 (공백문자로 끊어서 가져옴)
		String str2 = sc.nextLine();
		//String으로 입력 받아오기 (개행문자로 끊어서 가져옴)

		char[] charArr = sc.nextLine().toCharArray();
		char c = charArr[i];
		//String으로 입력 받아와서 Character 타입의 배열로 변환
		
	}
}

 

Scanner는 아주 간편하고 강력한 입력방법입니다.

내부적으로 입력을 parsing해서 여러 타입으로 변환하는 메소드들이 미리 구현되어 있기 때문에 간편하고 예외적인 상황을 통제하기도 좋지만, 시간이 오래 걸립니다. (trade off)

 

PS 문제들은 입력이 정확하게 규칙대로 주어지기 때문에 

풀이자가 입력의 예외를 잘 캐치하고 코드를 정확하게 작성했다면 Scanner를 사용하는 일은 괜히 동작 시간만 손해 보는 일이 될 수도 있습니다.

고난도의 PS 문제들은 입력의 개수가 10만, 100만 단위로 주어지기 때문에 A+B 같은 간단한 문제에선 신경 쓰이지 않던 시간 손해가 크리티컬 하게 작동할 수도 있기 때문입니다.

 

 

 

2. BufferedReader

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
//BufferedReader와 InputStreamReader 그리고 입출력 예외 IOException import

public class io_test {
	public static void main(String[] args) throws IOException {
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		//BufferedReader 선언하기
		
		String str = br.readLine();
		//String으로 입력 받아오기 (개행문자로 끊어서 가져옴)
		
		int i = Integer.parseInt(str);
		//String을 Integer로 parsing

		long l = Long.parseLong(str);
		//String을 Long으로 parsing

		double d = Double.parseDouble(str);
		//String을 Double로 parsing

		float f = Float.parseFloat(str);
		//String을 Float으로 parsing

		char[] charArr = str.toCharArray();
		char c1 = charArr[i];
		//String으로 입력 받아와서 Character 타입의 배열로 변환
		char c2 = str.charAt(i);
		//String으로 입력 받아와서 그 문자열의 index가 가리키는 Character 가져오기
	}
}

BufferedReader는 그 좋은 대안이 될 수 있습니다.

Buffered란 이름 그대로 버퍼에 입력을 쌓아두었다가 뭉탱이로 가져오는 놈이거든요.

대신 내부적인 타입 변환이 구현되어있지 않아 String, 또는 char[] 형태로 입력을 읽어옵니다.

 

가져온 값을 사용자가 직접 변환해주어야 하는데, 기본 타입 (Primitive type)들이나 기본적으로 재공 되는 Array, String 같은 Class 내부의 메소드를 이용해서 가능합니다.

 

하지만 이놈엔 문제가 있으니... 

input = "1 2 3" 과 같은 경우, Scanner는 nextInt()를 쓸 때마다 알아서 1,2,3을 가져왔던 반면 BufferedReader는 "1 2 3"의 String을 그대로 가져오게 되고, 이 String을 곧바로 parseInt에 넣는다면 에러가 나오게 됩니다.

parseInt는 하나의 숫자를 기대했는데, 들어온 값을 도무지 이해하기가 힘들기 때문이죠.

그래서 BufferedReader를 사용할 땐 StringTokenizer를 자주 같이 쓰게 됩니다.

 

3. BufferedReader + StringTokenizer

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
//BufferedReader와 InputStreamReader 그리고 입출력 예외 IOException import
import java.util.StringTokenizer;
//StringTokenizer import

public class io_test {
	public static void main(String[] args) throws IOException {
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		//BufferedReader 선언하기
		
		StringTokenizer st = new StringTokenizer(br.readLine());
		//br에서 가져온 String을 StringTokenizer로 쪼개기
		//기본적으로 공백문자로 쪼개지게 됨
		
		int a = Integer.parseInt(st.nextToken());
		int b = Integer.parseInt(st.nextToken());
		int c = Integer.parseInt(st.nextToken());
		//nextToken 메소드로 쪼개진 String을 가져옴
		
		System.out.println( a + ", " + b + ", " + c);
	}
}

위처럼 StringTokenizer를 사용해서 읽어온 String을 나누어 parsing 해주면, "1 2 3"같은 입력도 원하는 값으로 변환이 가능합니다.

 

StringTokenizer가 String을 쪼개는 기본적인 값은 공백문자이지만

StringTokenizer st = new StringTokenizer(br.readLine(), "a");

이런 식으로 쪼갤 delim을 지정해주게 되면

원하는 대로 String을 쪼개고 입력을 받을 수 있습니다.

또, hasMoreToken()과 같은 메서드로 남아있는 token이 있는지를 판별해 오류 없이 입력을 마무리할 수 있습니다.

 

출력


1. System.out.println

System.out.println("Hello JAVA");

정말 간단합니다. 기본적으로 제공되기 때문에 따로 import 할 패키지도 없습니다.

(Eclipse IDE 기준) sysout을 치고 ctrl+space를 누르면 자동으로 완성됩니다.

System.out.print(); 는 출력 문장의 뒤에 개행 문자 \n이 없고 System.out.println();은 기본적으로 줄 바꿈 하나가 들어가며 System.out.printf();는 c언어의 printf와 유사하게 format을 넣고 뒤에 그 안에 들어갈 변수들을 써서 사용할 수 있습니다.

 

간단한 프로그램에선 이 방법 만으로도 충분할 겁니다. 

하지만 출력이 수만, 수십만 개 반복되어야 하는 문제에선 출력 시간으로 인해 문제를 틀리는 경우가 생깁니다.

겉으로 보는 우리는 간편하고, 안정적이지만 메소드의 내부에선 출력마다 Sync와 Outputstream을 부르면서 시간을 잡아먹기 때문입니다.

(trade-off는 프로그래밍에서 뗄 수 없는 진리와도 같습니다.)

 

 

2. BufferedWriter

그래서 우리는 BufferedWriter를 사용할 수 있습니다. 이름을 보면 알 수 있듯, BufferedWriter는 BufferedReader의 출력 버전입니다. 

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class io_test {
	public static void main(String[] args) throws IOException{
		
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		//BufferedWriter 선언해주기! Reader와 마찬가지로 Stream의 import가 필요하다.
		
		bw.write("123\n");
		bw.write("456\n");
		bw.write("789\n");
		//Buffer에 출력할 값들을 쌓아놓는다.
		
		bw.flush();
		//쌓여있는 문장을 한 번에 출력!
		
		bw.close();
		//BufferedWriter를 닫아준다.
	}
}

사용법도 BufferedReader와 유사합니다.

여러 문장을 각각 출력하지 않고, Buffer에 Write해놓았다가 flush 메소드로 한 번에 출력하는 방법으로 시간을 단축합니다. 더 이상 BufferedWriter를 사용하지 않을땐 close해주는걸 잊지마세요!

 

 

3. System.out.println + StringBuilder

BufferedWriter 사용하기가 어렵게 느껴진다면, StringBuilder를 활용하는것도 좋은 방법입니다.

String을 하나로 만들어주는데 concat 메소드와 달리 시간이 많이 걸리지 않습니다. concat이 새로운 String객체를 계속 생성한다면 StringBuilder는 StringBuilder하나의 값들을 계속 이어 붙이는 방식입니다.

(JAVA 버전에 따라 + 연산이 내부적으로 concat으로도, StringBuilder로도 구현되어있다고 합니다. 헷갈리지 않게 하나로 통일감있게 사용합시다.)

public class io_test {
	public static void main(String[] args) {
		
		StringBuilder sb = new StringBuilder();
		//StringBuilder 선언, 따로 import할 package가 없다.
		
		sb.append("123 ");
		sb.append("456 ");
		sb.append("789\n");
		//StringBuilder에 출력할 문장을 계속 덧붙여준다.
		
		System.out.println(sb);
		//System.out.println(sb.toString());
		//출력한다. sb.toString()이 조금 더 명확하지만 그냥 출력해도 동작한다.
		
		//concat 메소드 예시
		 String str1 = "123 ";
		 str1 = str1.concat("456 ");
		 str1 = str1.concat("789\n");
		 
		 System.out.println(str1);
		 
		 //+연산 예시
		 String str2 = "123 "+"456 "+"789\n";
		 System.out.println(str2);
		
	}
}

출력된 결과는 모두 같습니다!

 

 

이상으로 JAVA의 입출력에 대해 설명을 마치겠습니다.

제가 쓴 내용은 기능적인 쪽에 중점을 두었고, Deep한 이론적인 내용은

 

JAVA [자바] - 입력 뜯어보기 [Scanner, InputStream, BufferedReader]

이 글을 지금 이 시점에 써야 할까 고민을 많이 했다. 사실 자바를 그냥 다룰 줄만 아는 것에 목표를 둔다면 이 글이 무의미할 수도 있다. 그러나 자바에 대해 조금이라도 관심이 있고 더 배우고

st-lab.tistory.com

이곳을 참고하시면 저어어엉말 잘 정리가 되어있습니다 ㅎㅎ

728x90

'🔠 Language > ☕ Java' 카테고리의 다른 글

[JAVA] 함수 Interface  (0) 2021.12.07
[JAVA] JAVA 배열 자주 쓰이는 코드 정리!  (0) 2021.11.30

안녕하세요!

드디어 SSAFY 1년 과정이 거의 마무리 되었고, 시간이 꽤 생길것 같기 때문에!

본격적으로 블로그에 포스팅을 작성하게 되었습니다.

 

제가 알고리즘 문제풀이 (Problem Solving)에 주로 사용하는 언어는 JAVA이지만

C++. Python 등으로도 종종 풀이가 올라갈 것 같습니다.

 

 

https://www.acmicpc.net/problem/1000

 

1000번: A+B

두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오.

www.acmicpc.net

 

 

아주 간단한 문제입니다.

백준에서 가장 많은 제출이 이루어진 문제기도 하고, 브론즈~실버 등급 대표 문제들의 정답률이 50%는 가뿐히 넘기는걸 생각하면 생각보다 정답률이 낮은 문제기도 합니다.

1000번 문제를 틀리는 이유는 여러개가 있습니다.

 

1. 진짜 프로그래밍 언어에 대해 하나도 모른다. 

2. 테스트케이스의 존재를 모르고 3을 출력하는 프로그램을 작성한다.

3. 자신이 작성한 언어가 아닌 다른 언어로 제출한다.

4. Main 함수, 또는 클래스의 이름을 잘못 설정한다.

5. 코드를 붙여넣는 과정에서 package, import등을 누락한다.

 

아무튼..

문제는 아주 간단합니다. 두개의 숫자를 입력받고, 덧셈연산의 결과값을 출력하면 됩니다.

 

import java.util.Scanner;

public class Main {
	
	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		
		int a = sc.nextInt();
		int b = sc.nextInt();
		
		System.out.println(a+b);
	}
}

 

이렇게요.

 

java 라이브러리 util 패키지의 Scanner 클래스를 import해주고

시스템의 입력인 System.in을 parameter로 새로운 Scanner 객체를 생성해주면 됩니다.

Scanner의 이름은 어떻게 정하셔도 상관없지만, 가독성과 다른 사람에게 코드를 공유할 때를 대비해 많이 사용하는 이름으로 선언해주시는게 좋습니다.

 

보통 기능적인 요소에서 따온 input, in 을 쓰기도 하고 Scanner 객체는 한 번 선언하고 계속 재사용하기 때문에 간단하게 scan, sc로 선언하기도 합니다. 

 

Scanner 클래스 안에는 여러가지 메소드가 들어있는데요.

간단한 문제이므로 입력으로 들어오는 다음 숫자를 반환하는 nextInt()를 통해 A와 B값을 받고

 

JAVA의 기본적인 출력함수인 System.out.println()을 통해 A+B를 출력했습니다.

 

조금 더 효율적인 입출력을 하고싶다! 하시는 분은

https://nodingco.tistory.com/7

 

[JAVA] PS에 유용하게 쓰이는 JAVA의 입출력 방법들

 

nodingco.tistory.com

 

이 글을 참고해주시면 감사하겠습니다!

728x90

코드를 작성한다.

어쩐지 오늘은 손에 날개라도 달린듯 손가락이 가볍게 움직인다.

내가 봐도 깔끔하고 잘 짜인 코드를 이제 Git에 올릴 시간이다.

Push 명령어를 입력하자 '띵~' 에러 소리가 울려퍼진다.

식은땀이 흐른다. 혹시 오타가 있을까 심혈을 기울여 다시 명령어를 입력한다.

띵~ 띵~ 띵띵띵띵~

fatal 'origin' does not appear to be a git repository

 

따옴표 안의 단어는 origin이 아닐수도 있다.

위 에러는 두가지 경우에 발생한다.

1. remote 저장소의 경로에 문제가 있을때

2. 내 branch 경로에 문제가 있을때

 

내 local 저장소는 remote 저장소의 복제본을 갖는다. 

코드를 작성하고 바뀐 파일들을 commit하는 것은 내 local 저장소의 branch를 수정하는 것이고, 이를 remote저장소에도 반영하기 위해서 Push가 필요하다. 이때 local 저장소의 branch 경로를 remote저장소와 비교한다.

위의 에러는 그 경로의 불일치로 발생한다.

 

1번의 경우 경로를 저장한 파일이 손상되었거나, remote의 경로가 변경되었거나 등의 이유로 remote저장소를 찾지 못하는상황이다. 

git remote remove 'origin' 명령어를 사용하여 remote 저장소의 경로를 지워주고

(설정에 따라 remote저장소의 경로가 origin이 아닐 수도 있다.)

git remote add origin (git repo의 HTTPS 주소, 혹은 SSH)를 입력해서 다시 연결해주면 된다.

 

2번의 경우 branch를 만들때 오타(otigin 이라던지... origim 이라던지)나 오류가 발생하여 local branch의 경로가 이상해진 상황이다. 변경 상황을 잘 commit 해 둔 뒤 branch의 이름과 경로를 잘 확인하고 다시 만들자.

에러가 난 branch를 지우는게 아니다. 다시 만드는 것이다. 

내가 만드려던 branch의 이름이 feature/FE 라고 했을때 에러가 난 상황에서 branch를 다시 만든다면

 

origin/feature/FE   (원래 만드려던 정상 branch)

feature/FE (에러 branch)

otigin/feature/FE (에러 branch)

 

내 local 저장소는 이런 상태가 된다.

제대로 만들어진 feature/FE로 checkout 해 주고 에러가 난 branch를 merge하자.

remote 저장소와의 경로 불일치로 동기화가 안 될 뿐 local에는 멀쩡히 존재하는 branch이므로 아무 문제없이 merge가 된다.

내가 변경한 코드가 잘 반영되었는지 확인하고 다시 Push해주면 된다.

 

 

 

 

728x90

'잡동사니 > GIT' 카테고리의 다른 글

VScode + Git사용시 자주 사용하는 커맨드 정리  (0) 2021.11.09

1. 잠을 자자 

 

평소 수면 시간의 80% 최소한 6시간 수면은 유지해줘야 머리가 쌩쌩 돌아갑니다. 

밤 새워서 하루를 코딩하는 것보다 적절히 휴식하면서 이틀 작업한 결과물이 질도 양도 훨씬 좋은 경우가 많았습니다.

물론 데드라인이 얼마남지 않았다면... 밤을 새야겠지만,

3일 이상 기한이 남았다면 수면을 취합시다. 개발은 마라톤입니다.

 

2. 카페인에 의존하지 말자.

 

하루 기준으로 아메리카노 두 잔(no설탕, no프림)이하를 마시는데 세 잔 이상을 마실 경우엔 기분이 너무 UP되어 코딩이 제대로 되지 않았습니다. ㅋㅋ

커피 대신 카페인이 비교적 적은 허브티와 홍차, 녹차류로 대체했습니다.

제일 좋은 건 Iced H2O라는 음료인데... 무려 0칼로리에 카페인이 존재하지 않습니다!

(네... 얼음물입니다... 죄송합니다...)

 

3. 휴대폰은 멀리하자.

우리는 스마트폰의 노예가 되지 않는다!

 

4. 가사 있는 노래는 금물...

 

흥얼거리는걸 넘어서 노래에 심취하게 됩니다.

개인적으론 피아노 곡이나 메이플스토리 OST를 즐겨듣습니다.

메이플스토리 게임 자체는 10년도 더 예전 초등학생 시절 이후로 하지 않았는데 노래는 즐겨 듣습니다.

 

아래 채널에 좋은 playlist가 많습니다. 홍보아님!

 

https://www.youtube.com/watch?v=-FMHYjqC4iA&ab_channel=PairPiano 

 

 

5. 막힐땐 도움을 구하자.

 

내 머리를 믿는것도 좋지만 아무런 배경지식 없이 천재들이 수백년간 쌓아온 지식을 따라잡는건 불가능합니다.

구글 선생님, 스택 오버플로우 선생님, 티스토리 선생님,

팀원이나 친구, 선배, 교수님, 나보다 코딩잘하는 후배든 상관 없습니다.

일단 물어봅시다.

728x90

'😃 My Story' 카테고리의 다른 글

첫 커리어, 첫 명함, 첫 출근(?) 모든게 다 처음  (0) 2022.08.17
코로나 걸려서 골골거렸습니다....  (0) 2022.03.13
싸피 SSAFY 5기 수료!  (0) 2021.12.21
SSAFY 5기를 마치고  (0) 2021.11.28
안녕하세요!  (0) 2021.11.01

+ Recent posts