1. 다운로드

Flutter로 앱 개발을 하기 위해서 필요한 위 제목의 3가지 프로그램을 설치해 볼 것이다.

 

1. Flutter 설치 홈페이지로 이동한다.

: Flutter | Install 로 이동한다.

2) 여기서 자신의 운영체제를 선택한다. 

그러면 다운로드 페이지가 나오는데, 이 한 페이지 안에서 필요한 3개의 프로그램을 모두 다운로드 받을 수 있다.

여기서는 Git -> Flutter -> Android Studio 순서대로 다운로드 받아 보겠다.

(지금까지는 Flutter와 Android Studio만 사용했고, 아직 Git을 어디에 사용하는지는 모른다. )

 

1. Git 다운로드

다음 화면에서 Git For Windows 를 클릭하면 클릭한 시점 당시의 최신 버전으로 Git을 다운로드 받을 수 있다. 

 

2. Flutter SDK 다운로드

: SDK를 다운로드 하는 것 = 그 언어를 사용하는 데 필요한 실행파일을 다운로드 하는 것.

즉 SDK를 다운로드해서 후에 Android Studio와 연결해 주면, Flutter 언어를 사용할 수 있게 된다. 

가장 최신 버전을 받을 수 있다.

 

3. Android Studio 다운로드

아래의 Android Studio라는 파란 글씨를 클릭한다. 

Flutter가 앱 프로그래밍 언어라면, Android Studio는 그 언어로 코딩을 도와주는 에디터(IDE라고 하는 것 같다)이다. 


2. 내 컴퓨터에서 사용할 수 있도록 추가 작업

: Flutter SDK 파일에 대한 작업

1. 다운로드 한 Flutter SDK의 zip 압축 파일을 풀어서 C드라이브 안에 저장하되, Program Files 폴더 안에는 저장하지 않도록 한다.

b/c Program Files 폴더 안의 파일들은 사용할 때 일정 이상의 보안? 요구조건을 충족해야 하는 경우가 있어서 그렇다.

2. Flutter에 직접 명령어를 주는 flutter_console.bat 이라는 배치 파일이 있다. 이 파일에서는 명령어를 입력하면 그에 따른 명령을 수행하는데, 기존 컴퓨터의 cmd(command prompt)와 기능이 비슷하다. 

그러면 Flutter에 명령을 줘야 할 때마다 이 flitter_console.bat 파일을 실행하기 번거롭다.

그래서 이 flutter_console.bat 에 입력할 내용을 cmd(사용자 pc의 일반 프롬프트)에 바로 입력해도 같은 결과로 명령을 수행하도록 해 줄 것이다.

 

+ 방법

1. 검색창에 제어판 입력 -> 열기

2. (사진에서는 세 번째 줄) 시스템 클릭

3. 창 우측의 고급 시스템 설정 클릭

4. 고급 탭의 환경 변수(N) 클릭

5. 위에서 Path 라는 변수를 클릭하고, 편집(E) 을 눌러서 경로를 추가한다. 

* "추가" 이다. 말 그대로 기존에 존재하던 경로를 삭제하면 안 되고, 그 뒤에다가 이어서 쓰라는 의미이다. 

* 이때 경로는 Flutter SDK가 현재 들어가 있는 경로로, C드라이브를 시작점으로 표현한다.

* 정확히는 압축을 푼 Flutter 폴더의 bin 파일을 기준으로 경로를 입력한다. 

나의 경우는 : ex.  C:\src\flutter\bin  <- 이렇게!

<-> 만약 Path라는 이름의 변수가 없다면, 새로 만들기(N)를 눌러서 만든 다음 경로로 위와 같이 추가해 주면 된다.


3. Android Studio와 같이 사용해서, 결과가 나오는지 확인해 보기!

1. Android Studio를 실행한다.

기본 상태에서는 실행 가능한 파일이 2개 있다: main.dart와 test.dart

이 중 test.dart만 실행해도 정상적으로 Flutter SDK를 통해 Android Studio가 실행되는지 확인할 수 있다.

이렇게 샘플 앱에 대한 코드가 나와 있다.

-> 이 앱이 그대로 실행된다면, 맞게 실행되는 것이다!

 

그런데 어떻게 실행할 것인가?

웹이 아니라 앱을 실행하는 것이므로, 테스트할 시험형 앱이 필요하다. 

 

2. 앱을 테스트하기 위한 장치가 필요하다. 

1. AVD Manager 아이콘을 클릭한다.

2. 가상 기기를 등록하는 화면이 나온다.

등록 가능한 가상 기기에는 여러 버전이 있다. 나는 그 중 Nexus 6 버전을 다운로드 받았다(강의에서 추천함)

등록되고 나면 이런 화면이 나오고, 여기서 재생 버튼을 누르면 이후 실행하는 Flutter 코드를 이 기기에서 테스트할 수 있게 된다. 

+ 나의 경우는 일반적이지는 않지만, 이런 메시지가 나온다:

알아보니 adb라는 배치 파일이 구형 버전이라서, 앱을 테스트할 수는 있지만 실행 속도가 느려서 경고가 발생한 것이었다. 조만간 adb 배치파일 업그레이드 하는 방법도 알아봐야겠다.

3. 테스트하는 경우이므로 2번의 가상기기가 등록된 상태에서, test.dart 메소드의 실행 버튼을 누른다.

이런 화면이 나오면 성공이다.

(gradle을 실행시키고 메소드를 실행하는 데 시간이 걸려서 어느 정도는 기다려야 한다.)

+ 위 앱은 아래의 + 버튼을 누르면 숫자가 0, 1, 2, .. 이렇게 1씩 증가하는 앱이다.

'server-side > Flutter' 카테고리의 다른 글

0. 시작  (0) 2021.09.03

공모전에 참여하면서 기존에 웹 개발을 목적으로 사용하던 java 언어가 아닌, 앱 개발을 통해 공모전을 준비하게 되었다.

=> 그래서 그나마 가장 많이 알고 있던 java 언어를 사용할 수 없었고, 앱을 만들기 위한 Flutter 라는 언어를 급하게(!) 준비하게 되었다.

Udemy 플랫폼의 flutter & dart 강좌를 부분부분 듣고 간략하게 정리해서, 앱의 백엔드 부분을 개발할 수 있도록 숙지하는 것이 목표이다.

다행인 점: java와 문법이 꽤 비슷한 듯.

'server-side > Flutter' 카테고리의 다른 글

#9 ~ #13. Flutter, Android Studio, Git 설치하기  (0) 2021.09.04

Step 9-1번 문제는 어제 풀었으므로 오늘은 생략.

 

Step 9-2번 문제(2581번).

**풀이에 참고한 블로그**

[백준] 2581번 : 소수 - JAVA [자바] (tistory.com)

 

[백준] 2581번 : 소수 - JAVA [자바]

https://www.acmicpc.net/problem/2581 2581번: 소수 M이상 N이하의 자연수 중 소수인 것을 모두 찾아 첫째 줄에 그 합을, 둘째 줄에 그 중 최솟값을 출력한다. 단, M이상 N이하의 자연수 중 소수가 없을 경우는

st-lab.tistory.com

중요1) 예제 데이터에서 원하는 출력이 나왔다고 되는 게 아니다. 백준 알고리즘은 아주아주 다양한 데이터를 내가 만든 알고리즘에 다 넣고, 이 데이터에서 모두 오류 없이 정확한 출력이 나왔을 때만 정답으로 인정한다.

=> 내가 모르는 다양한 입/출력 예시가 있고 그에 따른 실행 예외가 발생할 수 있으니 많은 것을 고려해야 한다...

하지만 나는 도무지 뭐가 잘못된 건지도 예상할 수 없었으므로... 다른 사람의 풀이를 분석해 보자.

 

핵심은, 소수를 구하기 위해서 사용하는 에라토스테네스의 체 알고리즘이었다!

특정 범위 안의 소수를 구할 때 하나씩 지워 나가고 아닌 것만을 남기는 알고리즘이다.

 

이때 코드를 보기 단순화시키려고 main 메소드의 밖에다가 따로 정적 메소드를 선언해서 알고리즘을 구현했다.

보통 인스턴스 메소드를 선언하면 객체를 따로 선언해야 해서 한 문제만 풀 때는 번거롭기도 하고 굳이 그럴 필요가 없어서 다들 정적 메소드를 사용하는 것 같다.

public static void get_prime() {
		prime[0] = true; // 소수 아니라서 제외
		prime[1] = true; // 소수 아니라서 제외
		for(int i=2; i<=Math.sqrt(prime.length); i++) {
			for(int j = (i*i); j<prime.length; j += i) {
				prime[j] = true;
			}
		}
	}

get_prime 메소드는 매개변수도 없고 출력값(리턴하는 값)도 없는 메소드인데, prime이라는 배열은 어디서 가져왔나?

get_prime() 메소드 위에다가 먼저 prime이라는 정적 boolean 타입의 필드를 선언해 주었다. 이렇게!

public static boolean[] prime; // main 메소드 밖에서 선언

나는 정적 필드를 선언할 생각은 못 했는데, 생각해 보니 정적 필드를 선언하고 그 필드를 정적 메소드에 언급하면 굳이 로컬변수나 객체를 생성하지 않아도 되겠다. 

 

이렇게 위에서 정적 필드를 선언하고, 나중에 main함수 안에서 prime 배열의 길이만 선언해 주면 된다.

N+1의 길이로 설정해서 0부터 N까지의 소수값 여부를 저장할 수 있는 배열을 만들어 준다.

(정적 필드 prime배열을 N+1의 길이로 설정한 것도, 그냥 0부터 N까지의 수들 중 소수를 다 구해버리고 나중에 M에서 N 사이에 있는 소수 값만 추출하기 위해서인 것 같다. prime배열을 M부터 N까지 선언한다면 기존 에라토스테네스의 체 알고리즘을 일부 변형해야 되서 번거로운 점도 있을 듯.)

prime = new boolean[(N+1)]; // main 메소드 안에서 설정

 

에라토스테네스의 체 알고리즘은 2개의 중첩 for문으로 구성된다.

 

1. 여기선 true이면 소수가 아니고 false면 소수라고 간주한다.

2. 이는 어떤 수배수는 모두 소수에서 제외한다는 원리를 이용한다. 

첫 번째 for문에서의 i는 어떤 수의 역할을 한다.

두 번째 for문에서의 j는 어떤 수의 배수 역할을 한다.

 

좀 더 구체적으로 보면,

1. 0과 1은 소수가 아니고 2는 소수라서, i=2부터 시작한다. 

2. j는 i*i이다. i*i는 i라는 약수를 갖기 때문에 소수에서 제외된다.

3. 이 j에다가 i씩 더한다. 즉 i*i, i*(i+1), i*(i+2), ... 이렇게 해서 i를 약수로 갖는 모든 값들을 제외시킨다.

4. 그 다음은 i=3, 위의 과정을 반복한다. 그런데 만약 i=4처럼 소수가 아닌 값이 i 자리에 와도 이미 i=2일 때 j의 값에 해당되어서 제외되었기 때문에 상관 없다.

5. 이렇게 N까지 반복하는 것이 아니라, N에 루트 씌운 값까지만 반복한다. 그 이후의 값은 검사할 필요가 없다.

 

+) 5번의 이유:

어떤 자연수 N은 1과 자신이 아닌 다른 두 수 A와 B의 곱으로 나타낼 수 있다고 해 보자. (즉 N은 소수가 아니다.)

A * B = N이다.

그런데 만약 A가 N의 제곱근보다 크다면, 나머지 B는 반드시 N의 제곱근보다 작아야 한다. 안 그러면 A*B는 N보다 큰 값을 갖게 되어서 식이 성립하지 않는다.

=> 즉 N이 소수가 아니라고 가정할 때, N의 제곱근까지만 검사하면 합성수 N을 이루는 두 수 A, B중 작은 수(여기서는 B)까지는 검사할 수 있고, 만약 여기까지 검사했을 때 N의 약수가 나오지 않는다면?

=> B가 없는 것이므로 A*B = N 이라는 가정이 깨지게 된다. 고로 이때 N은 소수가 아니라고 볼 수 있다.

=> N의 제곱근까지만 검사하면 N이 소수인지 아닌지를 알 수 있다!

 

아무튼 그래서 get_prime() 정적 메소드를 선언해서 N까지의 수 중에서 소수인 값만 찾아 준다.

 

그 다음에는 main함수에서 해결하면 되는데,

1. if문에서 최솟값인 M이 최댓값인 N보다 큰 예외 상황 및 M, N이 0과 10000 사이가 아닌 예외 경우를 따로 처리한다.

2. 초기 sum 값은 0, min값은 int 타입이 가질 수 있는 가장 큰 값으로 설정하고, 바꿔 나간다.

** 왜 min 값을 0이 아니라 최댓값으로 설정하는지는 잘 모르겠다...!

int sum = 0;
int min = Integer.MAX_VALUE;
// Integer 클래스 안에 MAX_VALUE라는 final static 필드가 선언되어 있어서 이렇게 불러올 수 있나보다.

그리고 정적 필드 prime의 각 원소를 for문을 사용해서 하나씩 해당 값이 false인지(=소수인지) 비교하는데, 만약 false라면 sum 값에다 더해 주고, min 값으로 할당해 준다.

for(int i=M; i<=N; i++) {
			if(prime[i]==false) {
				sum += i;
				if(min==Integer.MAX_VALUE) {
					min = i;
				}
			}
		}

이때, prime의 해당 원소의 값이 false일 때 min의 값을 i로 할당해 줘야 한다.

이렇게 조건을 주면, min값이 초기에 설정한 Integer.MAX_VALUE일 때만 min 값을 i로 할당하는데,

그러면 min값은 한 번만 할당되고 여러 번 변경되지 않는다.

 

마지막으로, 만약 M부터 N까지의 범위에 소수가 없었을 때, 즉 sum == 0일 때의 조건만 지정해 준다.

if(sum==0) {
			System.out.println(-1);
		}else {
			System.out.println(sum);
			System.out.println(min);
		}

이러면 문제가 풀린다....

 

<오답분석>

처음에 나는:

1. 에라토스테네스의 체 알고리즘을 쓰지 않고 (=> 효율성 문제)

2. min 값을 0으로 두고 (=> min값을 MAX_VALUE로 두지 않을 경우 오류가 발생되는 데이터가 있었을 것)

3. M, N이 지정한 데이터 값을 벗어났을 경우를 처리하지 않아서 에러가 발생하지 않았을까 생각해 본다.

 

<의문>

Q1. 왜 min 값을 0으로 설정하면 안 되는지는.... 정말 궁금하다. 

Q2. BufferedReader를 쓸 때 InputStreamReader를 같이 쓰는데, 그럼 InputStream과의 차이는 무엇일지 궁금하다.

 

Step 9-3번 문제(11653번).

주어진 자연수 N을 소인수분해하는 문제.

이번 문제는 혼자 풀었다!

'소수'가 키워드이나, 앞의 소수 판별 문제와는 다른 것이, 가령 거듭제곱으로 A의 k승인 경우 A를 1번만 출력하지 말고 k번 다 출력해야 했다. 그래서 조건이 맞으면 i가 증가하는 for문이 아니라 while문을 사용했다.

 

1. Import

import java.util.Scanner;
import java.util.ArrayList;

1. 입력을 받아야 하므로 Scanner(BufferedReader를 쓰지 않아도 시간 초과가 안 되었다.)

2. N의 약수에 해당하는 수를 저장할 ArrayList. 소인수가 몇 개일지 몰라서 배열 말고 ArrayList를 사용했다.

 

2. 정적 필드

9-2를 풀면서 정적 필드, 메소드를 잘 활용하면 객체 생성이나 로컬변수 처리 문제를 안 겪어도 된다는 생각에 정적 필드와 메소드를 선언했다.

public static int N;
public static ArrayList<Integer> number = new ArrayList<Integer>();
public static int i = 2;

1. N : scanner로 입력받을 N을 다른 메소드에서 다시 정의하기 귀찮아서 정적 필드로 선언.

2. ArrayList도 위에서 import만 해 주면 static field로 선언할 수 있었다...!

3. i는 while문에서 하나씩 증가시키고 해당 조건에 맞으면 소인수로 ArrayList에 추가시킬 수인데, 로컬 변수로 선언했다가 괜히 처리하기 까다로워질 것 같아서 정적 필드로 선언했다.

 

3. 정적 메소드 선언

자연수 N이 주어지면 해당 자연수를 소인수분해하는 isDivisor() 메소드를 선언하였다.

public static void isDivisor(int N) {
		if(N==1) { // 예외1 : N=1일 때
			System.out.println("");
		}else if(N<0 | N>10000000) { // 예외2 : N이 범위를 벗어날 때
				System.out.println("Error");
		}else {
			while(true) {
				if(N==i) { // case 1
					number.add(i);
					break;
				}else if(N % i != 0) { // case 2
					i++;
				}else if(N % i == 0) { // case 3
					N = N/i;
					number.add(i);
				}
			}
			for(int k=0; k<number.size(); k++) {
				System.out.println(number.get(k));
			}
		}
	}

case 1:

소인수분해가 다 완료되고 더 이상 인수(혹은 약수)가 없으면 나눠지고 남은 수인 N과 나눌 수인 i가 서로 같아진다. 이 경우에만 while문을 break하도록 했다.

case 2:

N이 i로 나눠지지 않을 때 = i가 N의 소인수가 아닐 때.

i+1을 해서 값만 변화시켰다.

case 3:

N이 i로 나눠질 때 = i가 N의 소인수일 때.

우선 N을 i로 나눠서 N 값을 변화시키고, 해당 i값을 ArrayList에 추가했다.

i값을 증가시키지 않았으므로, 만약 N이 i로 여러 번 나눠지는 수였다면 그만큼 i가 추가로 ArrayList에 추가되도록 했다.

 

그리고 이렇게 만들어진 number이라는 ArrayList를 0번부터 끝까지(ArrayList의 size -1까지) 출력시켰다.

 

4. main 메소드

앞에서 메소드와 필드로 모든 과정을 선언해서 main메소드는 짧게 작성할 수 있었다.

public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
		
		isDivisor(N); // 3번에서 작성한 isDivisor 정적 메소드 사용
		
		sc.close(); // scanner 꼭 닫아주기!
	}

 

Step 9-4. 소수 구하기(1929번)

이 문제도 혼자 풀었다.

 

<접근>

Step 9-2의 에라토스테네스의 체의 원리를 그대로 활용했다.

다만 아까는 int타입의 sum 변수를 사용한 대신, 지금은 에라토스테네스의 체로 0부터 N까지의 소수를 구한 뒤, M부터 N까지의 소수만 출력하는 방식을 사용하였다.

 

import java.util.Scanner;

public class Main {
	
    // 정적 필드 선언
    
	public static int M;
	public static int N;
	public static boolean[] prime;
	
	public static void main(String[] args) {
		
        // 정적 메소드에 사용할 값 할당하기
		Scanner sc = new Scanner(System.in);
		M = sc.nextInt();
		N = sc.nextInt();
		prime = new boolean[(N+1)];
		
		if(M>=1 && N>=M && N<=1000000) {
			get_prime(); // 정적 메소드 사용
            
            // 정적 메소드에서는 1~N의 소수를 구했으나, M~N의 소수만 출력
			for(int i=M; i<prime.length; i++) {
				if(prime[i]==false) {
					System.out.println(i);
				}
			}
		}else { // 예외처리 : M과 N의 범위가 잘못되었을 때
			System.out.println("ERROR");
		}
		
		sc.close();
	}
    
    // 정적 메소드 선언
	
	public static void get_prime() {
		prime[0] = true;
		prime[1] = true;
		for(int i=2 ; i<=Math.sqrt(N) ; i++) {
			for(int j=(i*i); j<prime.length; j += i) {
				prime[j] = true;
			}
		}
	}
	
}

 

Step 9-5(4948번)

이것도 혼자 풀었다! 사실 에라토스테네스의 체 원리만 알면 쉽게 풀 수 있는 문제인 것 같다.

 

<원리>

9-2, 9-4와 마찬가지로 에라토스테네스의 체 알고리즘은 정적 메소드로 선언해 놓은 상태에서 시작하면 편하다.

다만 여기는 여러 개의 test case가 주어지고, 각각 한 줄씩 주어지며, 몇 개가 주어질지 모른다는 점에서 주의해야 한다.

 

1. N의 입력 여러 개 받기

이때 N은 몇 개가 나올지 모르고 한 줄씩 나오므로, StringTokenizer 등을 사용하지 않아도 분리가 되었다. 나는 원래 분리된 걸 분리하려고 하느라 애를 먹었는데, 원래 스캐너는 입력을 하면 한 줄 단위로 처리하는 거였다.

다만 여러 줄을 입력하고 언제 끝날지 모른다는 점에서 for문보다는 while문이 사용하기 적합했다.

-> 그래서 main메소드 영역을 이렇게 작성했다.

public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		
		while(true) {
			N = Integer.parseInt(sc.nextLine().trim());
			if(N==0) {
				break;
			}
			if(N<1 | N>123456) {
				System.out.println("ERROR");
				break;
			}else {
				prime = new boolean[((2*N)+1)];
				get_prime();
			}
		}
		
		sc.close();
	}

입력의 마지막에 0이 주어진다는 말은, 0이 입력으로 주어지면 프로그램을 종료시키라는 말과 같다.

그래서 while문을 두고 break하는 조건을 N==0일 때로 지정했다.

+ 또한 N은 sc.nextLine()으로 입력을 한 줄씩 받아서 처리하도록 했다.

+ N 뒤에는 trim() 메소드를 써서, 혹시나 공백과 섞인 문자열이 들어갔을 때 숫자만 추출할 수 있도록 했다.

 

2. 에라토스테네스의 체 원리를 이용 + 문제에 맞게 get_prime 정적메소드 다시 정의

우선 정적 메소드에서 사용할 정적 필드를 먼저 정의했다.

public static int N; // main 메소드에서 입력 받을 때 사용
public static boolean[] prime; // 많은 숫자들 각각이 소수인지 아닌지를 저장하기 위한 배열
public static int count = 0; // 특정 범위에서 소수의 숫자를 세기 위한 int 타입 필드
public static void get_prime() {
		count = 0; // N이 새로 바뀌어서 메소드가 새로 호출될 때마다 count를 0으로 초기화한다.
		prime[0] = true;
		prime[1] = true;
		if(N==1) { // N=1이면 i=2로 시작해서 소수를 셀 수 없으므로 예외로 처리했다.
			System.out.println(1);
		}else if(N==0) {
			System.out.println("");
		}else { // 에라토스테네스의 체 알고리즘 그대로 사용
			for(int i=2 ; i<=Math.sqrt((2*N)) ; i++) {
				for(int j=(i*i); j<prime.length; j += i) {
					prime[j] = true;
				}
			}
			
            //N보다 크고 2N보다 작은 소수들만 출력
			for(int i=(N+1) ; i<=(2*N) ; i++) {
				if(prime[i]==false) {
					count ++; // 소수 하나 나올 때마다 count + 1
				}
			}
			System.out.println(count);
		}
	}

최종 코드는 이렇다.

package ml.app2;

import java.util.Scanner;

public class Main {
	
	public static int N;
	public static boolean[] prime;
	public static int count = 0;
	
	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		
		while(true) {
			N = Integer.parseInt(sc.nextLine().trim());
			if(N==0) {
				break;
			}
			if(N<1 | N>123456) {
				System.out.println("ERROR");
				break;
			}else {
				prime = new boolean[((2*N)+1)];
				get_prime();
			}
		}
		
		sc.close();
	}
	
	public static void get_prime() {
		count = 0;
		prime[0] = true;
		prime[1] = true;
		if(N==1) {
			System.out.println(1);
		}else if(N==0) {
			System.out.println("");
		}else {
			for(int i=2 ; i<=Math.sqrt((2*N)) ; i++) {
				for(int j=(i*i); j<prime.length; j += i) {
					prime[j] = true;
				}
			}
			
			for(int i=(N+1) ; i<=(2*N) ; i++) {
				if(prime[i]==false) {
					count ++;
				}
			}
			System.out.println(count);
		}
	}
}

 

Step 9-6(9020번)

다른 블로그의 글을 참고해서 풀었다!

참고한 글: [백준] 9020번 : 골드바흐의 추측 - JAVA [자바] (tistory.com)

 

[백준] 9020번 : 골드바흐의 추측 - JAVA [자바]

https://www.acmicpc.net/problem/9020 9020번: 골드바흐의 추측 문제 1보다 큰 자연수 중에서  1과 자기 자신을 제외한 약수가 없는 자연수를 소수라고 한다. 예를 들어, 5는 1과 5를 제외한 약수가 없기 때

st-lab.tistory.com

에라토스테네스의 체 알고리즘을 알고 있었으나, 여기서는 주어진 짝수를 소수의 합으로 나타내되, '두 소수의 차가 가장 적은 쌍으로 나타내라'는 조건이 추가적으로 붙어서 그 점이 어려웠던 것 같다. 그래도 내가 생각한 범위에서의 예제 데이터는 처리할 수 있었는데, 왜 오류가 난 것인지는 잘 모르겠다ㅠㅠ

* IndexOutOfBoundsException 예외가 특히 많이 나왔는데, 어디서 나왔는지를 모르겠다...!

 

일단 풀이 시작>>

 

<보완할 점>

블로그 글을 보면서 이해하니, 내 코드가 생각보다 많이 복잡했음을 알 수 있었다.

나는 주어진 짝수가 여러 소수의 합으로 나타낼 수 있고, 그게 총 몇 쌍일지를 모르므로 ArrayList 구조를 사용해야 한다고 생각했지만, while문 하나로도 간단하게 코드를 짤 수 있는 문제였다.

 

<기존 나의 풀이의 개선점>

: 사용하지 않아도 될 변수 + 자료구조가 꽤 많고, 코드가 복잡했다!

import java.io.*;
import java.util.ArrayList; // 사용할 필요가 없었다

public class Main {

	public static boolean[] prime = new boolean[10001];
	public static int n;
	public static ArrayList<Integer> goldberg; // 사용할 필요가 없었다
	public static int sub_index; // 사용할 필요가 없었다

	public static void main(String[] args) throws IOException {

		try { // 사용할 필요가 없었다
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
			int T = Integer.parseInt(br.readLine().trim());
			get_prime();
			for (int i = 0; i < T; i++) {
				n = Integer.parseInt(br.readLine().trim());
				goldberg = new ArrayList<Integer>(); // 사용할 필요가 없었다
				if (n > 10000 | n < 4) {
					bw.write("ERROR");
					break;
				} else {
					get_goldberg();
				}
			}
			bw.close();
		}catch(IndexOutOfBoundsException e) {
			System.out.println(e);
		}
	}

	public static void get_prime() {
		prime[0] = true;
		prime[1] = true;
		for (int i = 2; i <= Math.sqrt(10000); i++) {
			for (int j = (i * i); j < prime.length; j += i) {
				prime[j] = true;
			}
		}
	}

	public static void get_goldberg() throws IOException { // 사용할 필요가 없었음. 이 긴 걸!
		
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

		for (int i=3; i<=(n/2); i+=2) {
			if( prime[i]==false && prime[(n-i)]==false) {
				goldberg.add(i);
				goldberg.add((n-i));
			}else if(prime[i]==false && (2*i)==n) {
				goldberg.add(i);
				goldberg.add(i);
			}
		}
		int min = Integer.MAX_VALUE;
		int sub_index = 0;
		for (int i = 0; i < goldberg.size(); i += 2) {
			int sub = Math.abs(goldberg.get(i) - goldberg.get(i + 1));
			if (sub < min) {
				sub_index = i;
			}
		}
			bw.write(String.valueOf(goldberg.get(sub_index)) + " ");
			bw.write(String.valueOf(goldberg.get(sub_index + 1)) + "\n");
			bw.flush();
		
	}

}

 

<핵심>

1. 한 수의 합이 되는 두 수의 쌍 중 가장 차가 적은 것을 선택하려면, (블로그 글 보면서 배운점)

: 짝수 2N의 경우 N+N에서부터 시작하여, (N-1)+(N+1) 이런 식으로 첫 번째 수는 하나씩 감소, 두 번째 수는 하나씩 증가시킨다. 그러면 두 수의 차가 커지면서 두 수의 합은 그대로 유지된다. 이런 식으로 while문을 전개시키고, 두 수가 모두 소수가 되는 시점에 while문을 break하면 다른 변수를 생성하지 않아도 된다.

 

2. 주어진 짝수의 범위는 어차피 제한되어 있으니, 처음에 크기가 10001(10000+1)인 boolean 타입의 배열을 만들고 그 범위의 소수를 다 구하는 것이 매번 새로 배열을 만들고 소수를 새로 구하는 것 보다 빠르다. (당연하지만...!)

 

<코드 다시 작성>

import java.io.*;

public class Main {

	public static boolean[] prime = new boolean[10001];

	public static void main(String[] args) throws IOException {
		
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
			int T = Integer.parseInt(br.readLine().trim());
			get_prime();
			
			while(T>0) {
				int n = Integer.parseInt(br.readLine().trim());
				int firstNum = n/2;
				int secondNum = n/2;
				while(true) {
					if(prime[firstNum]==false && prime[secondNum]==false) {
						System.out.println(firstNum + " " + secondNum);
						break;
					}
					firstNum--;
					secondNum++;
				}
				T--;
			}
			
			bw.close();
	}

	public static void get_prime() {
		prime[0] = true;
		prime[1] = true;
		for (int i = 2; i <= Math.sqrt(10000); i++) {
			for (int j = (i * i); j < prime.length; j += i) {
				prime[j] = true;
			}
		}
	}

}

 

 

 

 

 

 

 

'server-side > JAVA Algorithm' 카테고리의 다른 글

Chapter 4-1 if문  (0) 2021.05.04
Chapter 3  (0) 2021.05.03

1. For문

1. for문 기본실행

public static void main(String[] args) {
		int sum = 0;
		for(int i=1; i<=100; i++) {
			sum += i;
		}
		System.out.println(sum);
	}

* for문은 연속하는 수의 합을 구할 때도 많이 사용한다.

=> 이럴 때는 += 등의 증감연산자를 사용할 수 있다.

 

2. for문 안에서 정의된 변수는 로컬 변수(local variable)로, for문 밖으로 값을 갖고 나올 수 없다.

오류 예시!

public static void main(String[] args) {
		for(int i=1; i<=100; i++) {
			sum += i;
		}
		System.out.println(sum);
	}

* 이 코드는 실행시키면 오류가 난다.

: b/c sum 변수는 for문 안에서 정의되었는데, for문 바깥에서 사용하려고 하면 sum변수 값을 불러올 수 없다.

=> sum변수를 for문 밖에서도 사용하고 싶다면, for문이 시작하기 이전에, 즉 for문 밖에서 정의를 먼저 해 주면 된다.

 

3. for문 : 초기화식, 조건식, 증감식에 각각 두 개 이상의 변수 넣기

public static void main(String[] args) {
		int sum = 0;
		for(int i=1, j=100; i<=100 && j>=50 ; i++, j--) {
			sum = sum + i * j;
		}
		System.out.println(sum);
	}

* for문의 ()안에는 여러 변수들의 초기화식, 조건식, 증감식이 들어갈 수 있다.

* for (변수1 초기화식, 변수2 초기화식 ; 변수1 조건식 (&&/|) 변수2 조건식 ; 변수1 증감식, 변수2 증감식) 이렇게!

 

4. for문 변수로 float타입을 사용하지 않는 게 좋다.

그 이유는?

public static void main(String[] args) {
		for (float k = 0.1f ; k<=1 ; k+=0.1f) {
			System.out.println(k);
		}
	}

: 이론상 초기화식에서 k=0.1이고 0.1씩 더해서 1까지 실행하므로 10번을 실행하는 게 맞다.

하지만 for문은 9번 실행되었는데, 그 이유는 float는 부동 소수점을 사용하기 때문에 0.1을 정확하게 표현하지 못하고, 실제로는 0.1보다 조금 큰 값을 k에 더하게 된다. 그래서 9번만 실행된다.

 

5. 중첩 for문

: for문 안에 또 다른 for문을 쓸 수 있다. 중첩에 대해서 개수 제한은 없는 듯 하다.

중첩 for문을 이용해서 구구단을 작성해 보았다.

public static void main(String[] args) {
		for(int m=2 ; m<=9 ; m++) {
			System.out.println("*** " + m + "단 ***");
			for (int n=1 ; n<=9 ; n++) {
				System.out.println(m + "x" + n + "=" + (m*n));
			}
		}
	}

 

2. while문

while문과 for문은 기본적으로 같은 반복문이라서 for문으로 작성할 수 있는 코드는 while문으로도 작성할 수 있다.

다만 for문은 반복할 횟수만큼 반복시키는 경우가 많고, while문은 특정 조건에 해당할 때만 코드를 실행한다는 점에서 차이가 있다.

1. while문으로도 for문처럼 연속되는 숫자의 합을 구할 수 있다.

public static void main(String[] args) {
		int i=1; int sum = 0;
		while (i<=10) {
			sum += i;
			System.out.println(sum);
			i++;
		}
	}

 

2. while문은 해당 조건을 만족하면 실행문이 무한히 실행되어 루프가 발생할 수 있다. -> 주의!

public static void main(String[] args) {
		int i=3; int sum = 0;
		while (i>=2) {
			sum += i;
			System.out.println(sum);
			i++;
		}
	}

* i>=2 를 만족하면 while문은 계속 실행된다. 그런데 초기값이 i=3이고, i++으로 계속 i가 증가하므로 계속 이 조건을 만족하게 된다.

=> 이 경우 Terminate 버튼을 눌러서 강제 종료하지 않으면 무한히 실행된다.

 

+ while문에 딱히 작성할 조건이 없을 때?

-> while(true) 로 작성하고, 중간에 if() {break;} 를 작성하는 방법도 있다.

 

* for문과의 차이점-1

: while는 for문처럼 초기화식이 없기 때문에, 반복문에 넣을 변수를 while문 전에 미리 선언해 주어야 한다.

public static void main(String[] args) {
		int i=1; int sum = 0;
		while (i<=100) {
			sum += i;
			i++;
		}
		System.out.println(sum);
	}

-결과 : 5050

* for문과의 차이점-2

: while문은 for문처럼 증감식이 없다. 그래서 증감연산자를 어디에 배치하는지에 따라 결과값이 달라질 수 있다.

위의 식과 증감연산자의 위치만 다르게 해 보면, (증감연산자를 위에 배치)

public static void main(String[] args) {
		int i=1; int sum = 0;
		while (i<=100) {
			i++;
			sum += i;
		}
		System.out.println(sum);
	}

-결과 : 5150

* 중간에 i++ 처럼 증감문을 써 주지 않으면, 반복 변수의 값이 동일한 채 무한루프가 발생한다.

흔히 발생하는 실수이므로 주의!!

 

3. 반복문을 멈추는 또 다른 방법 : break;

break ; 는 for, while, do-while, switch문 등 다양한 구문에 사용할 수 있다.

break; 를 사용하면 반복문을 빠져나올 수 있다!

그러나 if() 을 사용해서, 어느 상황에 break;를 실행할지를 명시해 주어야 사용할 수 있다.

ex) 1부터 30까지의 합을 구하는데, 중간에 7과 3의 최소공배수를 만나면 반복문 빠져나오기

public static void main(String[] args) {
		int i=1; int sum=0;
		while(i<=30) {
			sum = sum + i;
			i++;
			if(i == 7*3) {
				break;
			}
		}
		System.out.println(i + " " + sum);
	}

 

4. while문과 비슷한 do-while문

: while문은 () 안의 조건이 참이면 그 다음에 실행문으로 넘어가지만,

do-while문은 do{} 안의 실행문을 먼저 실행하고, 그 다음에 while()의 조건이 맞는지 확인한다.

위와 같은 상황을 do-while문으로 코딩해 보았다.

public static void main(String[] args) {
		int i=1; int sum=0;
		do {
			sum += i;
			i++;
		}while(i!=7*3);
		System.out.println(sum);
	}

* 원래 while문과 비교해 보면,

while 안의 ()와 if() 부분의 조건절 부분은 전부 while 안의 ( ) 로 이동하고,

그 외의 '조건이 맞았을 때'의 실행문은 전부 do 안의 { } 로 이동한다.

 

5. 증감식의 경우, char 타입 변수도 사용 가능하다.

public static void main(String[] args) {
		for(char upper='A'; upper<='Z'; upper++) {
			for(char lower='a'; lower<='z'; lower++) {
				System.out.println(upper + "-" + lower);
			}
		}
	}
}

: for문의 경우, 초기식을 char변수의 알파벳으로 설정하고,

증감식에 ++를 표현했더니 알파벳 순서대로 A,B,C, ..., Z 까지 출력되는 것을 볼 수 있다.

 

6. continue : break;와 반대 역할

: 특정 조건을 만족했을 때만 결과를 실행한다.

public static void main(String[] args) {
		for(int i=1;i<=100;i++) {
			if(i%2 == 0) {
				continue;
			}
			System.out.println(i);
		}
	}

 

위의 경우, i%2!=0 인 경우에는 결과로 출력되지 않는다.

+ continue; 와 break; 모두 if() 안에 조건을 입력해야만 실행할 수 있다.

 

'server-side > JAVA' 카테고리의 다른 글

Chapter 4  (0) 2021.05.04

Baekjoon 단계별 문제풀이 - if문의 5문제 풀어봄.

1. [1330] 두 수 비교하기

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int A = scanner.nextInt();
		int B = scanner.nextInt();
		if(A<=10000 && A>=-10000 && B<=10000 && B>=-10000) {
			if(A>B) {
				System.out.println(">");
			}else if(A==B) {
				System.out.println("==");
			}else if(A<B) {
				System.out.println("<");
			}
		}else {
			System.out.println("ERROR");
		}
		scanner.close();
	}
}

2. [9498] 시험 성적 비교하기

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int grade = scanner.nextInt();
		if (grade>=0 && grade<=100) {
			if(grade>=90) {
				System.out.println("A");
			}else if(grade>=80) {
				System.out.println("B");
			}else if(grade>=70) {
				System.out.println("C");
			}else if(grade>=60) {
				System.out.println("D");
			}else {
				System.out.println("F");
			}
		}else {
			System.out.println("ERROR");
		}
		scanner.close();
	}
}

3. [2753] 윤년

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int year = scanner.nextInt();
		if(year>=1 && year<=4000) {
			if((year%4 == 0 && year%100 !=0)|(year%400 == 0)) {
				System.out.println(1);
			}else {
				System.out.println(0);
			}
		}else {
			System.out.println("ERROR");
		}
		scanner.close();
	}
}

* '배수', '약수' 등의 문제는 나머지 연산자 %을 이용하면 간단하게 코드 작성할 수 있다.

* and조건을 묶고, or 조건을 바깥에 쓰는 등 () 괄호를 이용하면 여러 연산자를 섞어서 한 줄로 조건을 만들 수 있다.

4. [14681] 사분면 고르기

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int x = scanner.nextInt();
		int y = scanner.nextInt();
		if(x>=-1000 && x<=1000 && x!=0 && y>=-1000 && y<=1000 && y!=0 ) {
			if(x>0 && y>0) {
				System.out.println(1);
			}else if(x<0 && y>0) {
				System.out.println(2);
			}else if(x<0 && y<0) {
				System.out.println(3);
			}else if(x>0 && y<0) {
				System.out.println(4);
			}
		}else {
			System.out.println("ERROR");
		}
		scanner.close();
	}
}

5. [2884] 알람 시계

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int H = scanner.nextInt();
		int M = scanner.nextInt();
		if (H>=0 && H<=23 && M>=0 && M<=59) {
			if(M<45 && H==0) {
					System.out.println(23+" "+(M+15));
			}else if(M<45 && H!=0) {
					System.out.println((H-1)+" "+(M+15));
			}else {
				System.out.println(H+" " + (M-45));
			}
		}else {
			System.out.println("ERROR");
		}
		scanner.close();
	}
}

대부분의 상황에서는 M-45를 하면 되는 간단한 상황이지만, 

1) H = 0일 때

2) M < 45일 때

3) H!=0 이고 M>=45일 때

위의 1)과 2)는 다른 처리를 해 줘야 하는 상황이다.

그래서 특수한 경우인 1), 2)를 앞의 if와 else if에 할당하고, 나머지 모든 경우인 3)은 else에 할당하였다.

 

'server-side > JAVA Algorithm' 카테고리의 다른 글

Step.9 : 9-1 ~ 9-6  (0) 2021.06.05
Chapter 3  (0) 2021.05.03

1. 조건문

1-1. IF문

1) 해당 조건에 대한 실행할 실행문이 하나라면 {}를 생략해도 좋지만, 그 이외에는 다 {}를 넣어야 한다.

	public static void main(String[] args) {
		int score = 91;
		
		if (score >=90) {
			System.out.println("You are Level A.");
			System.out.println("Congratulations!");
		}
		if (score <80) 
			System.out.println("You are Level B."); System.out.println("Keep up the good work");
			System.out.println("Try a little harder!");
	}

이렇게 if문 바로 아래 줄에, 같은 줄에 실행문을 두 개 이상 적는다고 해도, {}가 없으면 if문은 맨 앞의 실행문만 if문에 적용시킨다.

2) IF문으로 성적이 나오는 프로세스를 비슷하게 따라 해 보았다.

import java.util.Scanner;

public class chapter_4 {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		System.out.println("What's your midterm score?");
		int midterm = scanner.nextInt();
		System.out.println("What's your assignment score?");
		int assignment = scanner.nextInt();
		System.out.println("What's your team project score?");
		int team_project = scanner.nextInt();
		System.out.println("What's your final exam score?");
		int final_exam = scanner.nextInt();
		double score = midterm*0.3 + assignment + team_project*0.3 + final_exam*0.3;
		
		System.out.println("Your entire score is " + score);
		
		if (score >=90) {
			String grade = "A";
			System.out.println("Your grade is " + grade);
		}else if (score >=80){
			String grade = "B";
			System.out.println("Your grade is " + grade);
		}else if (score >=70) {
			String grade = "C";
			System.out.println("Your grade is " + grade);
		}else if (score >=60) {
			String grade = "D";
			System.out.println("Your grade is " + grade);
		}else {
			String grade = "F";
			System.out.println("Your grade is " + grade);
		}
		scanner.close();
	}

}

* 갑자기 생각나서 써봄

: printf()에서 여러 개의 형식과 여러 출력을 한꺼번에 지정할 때는 버전 오류가 난다!

Java se 11 이전 버전에서는 잘 작동하는지 궁금했지만 Oracle 회원가입을 해서 깔아야 한다니 참으로 귀찮은 일이 아닐 수 없다.

그래서 printf 함수는 사용을 안 하기로 했다. 어차피 백준에서는 Java se 11에 맞게 코드가 잘 작동된다고 한다.

 

3) 아쉽지만 printf 대신 println으로 로또번호 출력기를 만들어 봄

public static void main(String[] args) {
		int num1 = (int) (Math.random()*45 +1);
		int num2 = (int) (Math.random()*45 +1);
		int num3 = (int) (Math.random()*45 +1);
		int num4 = (int) (Math.random()*45 +1);
		int num5 = (int) (Math.random()*45 +1);
		int num6 = (int) (Math.random()*45 +1);
		
		System.out.println(num1);
		System.out.println(num2);
		System.out.println(num3);
		System.out.println(num4);
		System.out.println(num5);
		System.out.println(num6);
	}
}

: Math.random() <- 대문자 필수!

얘는 double 타입의 0부터 1 사이에 있는 난수를 발생시키는데, *45를 하고 1을 더해준 다음 강제로 int 타입으로 변환시킨다. 그러면 1부터 45사이에 값을 갖는 로또 번호 랜덤 생성기가 된다.

4) 치밀하게 설계하면 주사위 게임도 가능한 듯.

public static void main(String[] args) {
		int dice = (int)(Math.random()*6 +1);
		if(dice == 1) {
			System.out.println("1칸 전진하시오.");
		}else if(dice == 2) {
			System.out.println("무인도입니다. 한 턴 쉬어가세요.");
		}else if(dice == 3) {
			System.out.println("상대편의 말을 잡았습니다. 한번 더 굴리세요.");
		}else if(dice == 4) {
			System.out.println("통행료로 100,000원을 제출하세요.");
		}else if(dice == 5) {
			System.out.println("해당 영토의 건물을 살 수 있습니다. 구매하시겠습니까?");
		}else{
			System.out.println("결승점에 도착했습니다. 게임이 끝납니다.");
		}
	}

1-2. Switch문

똑같은 주사위 게임을 Switch문을 이용해서 만들 수 있다.

public static void main(String[] args) {
		int dice = (int)(Math.random()*6 +1);	
		switch(dice) {
		case 1:
			System.out.println("1칸 전진하시오.");
			break;
		case 2:
			System.out.println("무인도입니다. 한 턴 쉬어가세요.");
			break;
		case 3:
			System.out.println("상대편의 말을 잡았습니다. 한 턴 더 굴리세요.");
			break;
		case 4:
			System.out.println("통행료로 100,000원을 제출하세요.");
			break;
		case 5:
			System.out.println("해당 영토의 건물을 살 수 있습니다. 구매하시겠습니까?");
			break;
		default:
			System.out.println("결승점에 도착했습니다. 게임이 끝납니다.");
			break;
		}
	}

오히려 Switch문은 숫자 형태의 값을 갖는 변수를 사용하므로, 코드가 더 간단하게 작성될 수 있다.

+ 복잡하게 실행하면 진짜 주사위 게임도 가능할 듯.

+ 미연시 게임?처럼 대답에 따라서 스토리가 달라지는 게임도 가능할 듯.

 

Switch문의 대상인 변수의 값에 따라 출력되는 결과를 다르게 하고 싶다면, 

반드시 각 case마다 break; 문을 작성해야 한다!!

그렇지 않으면 이렇게 된다. ↓

public static void main(String[] args) {
		int dice = 2;
		
		switch(dice) { 
		case 1:
			System.out.println("1칸 전진하시오.");
		case 2:
			System.out.println("무인도입니다. 한 턴 쉬어가세요.");			
		case 3:
			System.out.println("상대편의 말을 잡았습니다. 한 턴 더 굴리세요.");		
		case 4:
			System.out.println("통행료로 100,000원을 제출하세요.");			
		case 5:
			System.out.println("해당 영토의 건물을 살 수 있습니다. 구매하시겠습니까?");			
		default:
			System.out.println("결승점에 도착했습니다. 게임이 끝납니다.");
		
		}
	}

: switch문의 변수인 dice는 2이다. 그런데 switch문의 case 사이마다 변수가 없어서, 각 case가 구분되지 않고 위에서부터 아래로 차례대로 코드가 실행되어서 이처럼 여러 경우에 해당하는 결과들이 다 같이 나오고 있다.

 

1) switch문의 변수 : char 타입의 입력 받기

import java.util.Scanner;

Scanner scanner = new Scanner(System.in);

char alphabet = alphabet.next().charAt(0);

+ char타입은 nextInt 등의 기능이 없다. 그래서 next() 다음에 charAt()을 입력한다.

+ 그런데 charAt(0) 에서 0의 의미가 무엇인지는 잘 모르겠다.

import java.util.Scanner;

public class chapter_4 {

	public static void main(String[] args) {
		System.out.println("What's your code?");
		Scanner scanner = new Scanner(System.in);
		char alphabet = scanner.next().charAt(0);
		
		switch(alphabet) { 
		case 'a':
			System.out.println("1칸 전진하시오.");
			break;
		case 'b':
			System.out.println("무인도입니다. 한 턴 쉬어가세요.");
			break;
		case 'c':
			System.out.println("상대편의 말을 잡았습니다. 한 턴 더 굴리세요.");
			break;
		case 'd':
			System.out.println("통행료로 100,000원을 제출하세요.");
			break;
		case 'e':
			System.out.println("해당 영토의 건물을 살 수 있습니다. 구매하시겠습니까?");
			break;
		default:
			System.out.println("결승점에 도착했습니다. 게임이 끝납니다.");
			
		}
	}
}

2) Switch문의 변수 : String 타입의 입력 받기

import java.util.Scanner;

Scanner scanner = new Scanner(System.in);

String str = scanner.nextLine();

+ 그런데 nextLine 코드를 사용할 때, 공백을 인식/인식하지 못해서 생기는 불편함에 대해서는 나중에 알아보자.

import java.util.Scanner;

public class chapter_4 {

	public static void main(String[] args) {
		System.out.println("What's your code?");
		Scanner scanner = new Scanner(System.in);
		String code = scanner.nextLine();
		
		switch(code) { 
		case "Apple":
			System.out.println("1칸 전진하시오.");
			break;
		case "Banana":
			System.out.println("무인도입니다. 한 턴 쉬어가세요.");
			break;
		case "Carrot":
			System.out.println("상대편의 말을 잡았습니다. 한 턴 더 굴리세요.");
			break;
		case "Daisy":
			System.out.println("통행료로 100,000원을 제출하세요.");
			break;
		case "Egg":
			System.out.println("해당 영토의 건물을 살 수 있습니다. 구매하시겠습니까?");
			break;
		default:
			System.out.println("결승점에 도착했습니다. 게임이 끝납니다.");
			
		}
	}
}

공백을 잘 인식하는지를 보기 위해서, String 변수의 각 case값을 2어절 이상의 단어로 설정했다.

import java.util.Scanner;

public class chapter_4 {

	public static void main(String[] args) {
		System.out.println("What's your code?");
		Scanner scanner = new Scanner(System.in);
		String code = scanner.nextLine();
		
		switch(code) { 
		case "Apple Juice":
			System.out.println("1칸 전진하시오.");
			break;
		case "Banana Smoothie":
			System.out.println("무인도입니다. 한 턴 쉬어가세요.");
			break;
		case "Carrot Cake":
			System.out.println("상대편의 말을 잡았습니다. 한 턴 더 굴리세요.");
			break;
		case "Daisy Tea":
			System.out.println("통행료로 100,000원을 제출하세요.");
			break;
		case "Egg Tart":
			System.out.println("해당 영토의 건물을 살 수 있습니다. 구매하시겠습니까?");
			break;
		default:
			System.out.println("결승점에 도착했습니다. 게임이 끝납니다.");
			
		}
	}
}

공백은 잘 인식하는 것 같다. 그리고 String 타입의 경우 정확한 string을 입력해야 한다! 대소문자도 구분한다!

ex) 'Egg Tart'를 대소문자 구분, 정확히 입력해야지만 해당 결과가 나온다

-> egg tart (X) , Egg Tart (O)

 

+ Scanner에는 여러 method가 있다.

ex) int 타입 변수 입력 시에는 nextInt 를 쓰는 것처럼!

=> String 타입 변수 입력시에는 .next 또는 .nextLine 를 사용하는데, 둘 사이에 차이가 있다.

1) scanner.next();

띄어쓰기 이후의 입력은 받아들이지 않는다.

각 입력의 구분 단위가 \n처럼 띄어쓰기인 것 같다.

import java.util.Scanner;

public class chapter_4 {

	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		String data = input.next();
		System.out.println(data);
		input.close();
	}
}

2) scanner.nextLine();

띄어쓰기 이후의 입력을 받아들인다.

각 입력의 구분 단위가 enter 즉 줄바꿈인 것 같다.

 

'server-side > JAVA' 카테고리의 다른 글

Chapter 4-2  (0) 2021.05.05

Baekjoon 단계별 문제풀이 중 "사칙연산" 카테고리 11문제 풀이

(일부는 풀이 적는 거 까먹어서 1,2,3,4,5,6,10,11번만 있음)

package ml.app2;

import java.util.Scanner;

public class chapter_3 {

	public static void main(String[] args) {	
		System.out.println("#1");
		System.out.println("Hello World!");
		System.out.println("\n\n#2");
		System.out.println("강한친구 대한육군");
		System.out.println("강한친구 대한육군");
		System.out.println("\n\n#3");
		System.out.println("\\    /\\");
		System.out.println(" )  ( ')");
		System.out.println("(  /  )");
		System.out.println(" \\(__)|");
		System.out.println("\n\n#4");
		System.out.println("|\\_/|");
		System.out.println("|q p|   /}");
		System.out.println("( 0 )\"\"\"\\");
		System.out.println("|\"^\"`    |");
		System.out.println("||_/=\\\\__|"); 
		System.out.println("\n\n#5\n");
		Scanner scanner = new Scanner(System.in);
		int A = scanner.nextInt();
		int B = scanner.nextInt();
		if(A>0 && B<10) {
			int result1 = A + B;
			System.out.println("A+B= " + result1);
		}else {
			System.out.println("ERROR!");
		} 
		System.out.println("\n\n#6\n");
		int C, D;
		C = scanner.nextInt();
		D = scanner.nextInt();
		if(C>0 && C<10 && D>0 && D<10) {
				int result2 = C - D;
				System.out.print(result2);
		}else {
				System.out.println("ERROR!");
		}
		System.out.println("\n\n#10\n");
			int E = scanner.nextInt();
			int F = scanner.nextInt();
			int G = scanner.nextInt();
			if(E>=2 && E<=10000 && F>=2 && F<=10000 && G>=2 && G<=10000) {
				int result3 = (E+F)%G;
				int result4 = ((E%G)+(F%G))%G;
				int result5 = (E*F)%G;
				int result6 = ((E%G)*(F%G))%G;
				
				System.out.println(result3);
				System.out.println(result4);
				System.out.println(result5);
				System.out.println(result6);
			}else {
				System.out.println("ERROR!");
			} 
		System.out.println("\n\n#11\n");
		int H = scanner.nextInt();
		int I = scanner.nextInt();
		if (H>=100 && H<1000 && I>=100 && I<1000) {
			int result7 = H*(I%10);
			System.out.println(result7);
			int result8 = H*((I%100)-(I%10));
				if (result8 == 0) {
					System.out.println(0);
				}else {
					System.out.println(result8/10);
				}
			int result9 = H*(I-(I%100));
				if (result9 == 0) {
					System.out.println(0);
				}else {
					System.out.println(result9/100);
				}
			int result10 = result7 + result8 + result9;
			System.out.println(result10);
		}else {
			System.out.println("ERROR");
		}
		scanner.close();
	}
}

정리

#5, #6

5번, 6번문제는 정수를 입력으로 받아서 scanner.nextInt(); 를 사용했다.

그러나 만약 정수가 아니라 문자열, String을 입력으로 받았더라면 상황이 복잡했을 수 있다.

nextInt의 경우, 숫자와 숫자 사이의 공백을 입력으로 받아들이지 않고 숫자만을 입력으로 받아들인다면,

String을 입력으로 받는 경우 두 입력 사이의 공백 등이 받아들여졌을 수 있다.

#11

세 자리 자연수 A, B를 입력으로 받되, 계산 과정에서 B의 각 자릿수의 숫자가 필요한 문제였다.

나는 String.valueOf() 과 .substring을 이용해서 int 타입의 B를 string으로 바꾼 다음 각 자릿수를 출력하려고 했으나, 훨씬 더 간단한 방법이 있었다.

=> abc라는 세 자리 자연수가 있을 때, %을 이용하면 각 자릿수를 쉽게 출력할 수 있다.

일의자리) abc % 10 = c.

십의자리) abc % 100 = bc. (abc*100)-(abc%10) = bc-c = b0. b0 / 10 = b.

백의자리) abc-(abc%100) = abc-bc = a00. a00 / 100 = a.

 

또한 input을 받기 위해 Scanner method를 사용했다면, 코드가 끝날 때 닫아줘야 한다!

scanner.close(); <-이렇게.

 

'server-side > JAVA Algorithm' 카테고리의 다른 글

Step.9 : 9-1 ~ 9-6  (0) 2021.06.05
Chapter 4-1 if문  (0) 2021.05.04

+ Recent posts