안녕하세요, 여행벌입니다.

 이번 포스팅에서는 리터럴(Literals)이 무엇이고 자바에서는 숫자를 어떻게 보기로 약속했는지, 그에 따라 앞에서 다룬 double, float, long 같은 자료형을 어떻게 활용할 수 있는지에 대해 다뤄보겠습니다.


리터럴(Literals)


int num = 157;

위의 코드에서 대입 연산자의 오른편에 위치한 숫자 157을 가리켜 '리터럴' 또는 '리터럴 상수'라고 합니다.

 

자바의 정수 표현에는 byte, short, int, long 네 가지 표현 방법이 있는데 그러면 정수형 리터럴 상수를 컴파일러는 어떻게 인식할까요?? 또, 실수 표현에도 float, double 두 가지 표현 방법이 있는데 실수형 리터럴 상수를 어떻게 인식할까요? 이렇듯 숫자를 접했을 때 이를 '무엇으로 인식할지에 대한 일종의 약속'이 필요하고, 이 약속에 근거하여 표현된 숫자를 '리터럴' 또는 '리터럴 상수'라고 합니다.


정수형 리터럴(Literals)


 자바에서는 정수형 숫자들은 모두 int 형으로 인식합니다. 저번 포스팅에서 다룬 '자바는 정수형 연산을 기본적으로 int형으로 진행한다' 와 같은 맥락입니다. 따라서, 다음과 같은 상황은 오류가 발생합니다.

long num = 999999999999; // int 형 범위를 넘어가는 리터럴상수

 위의 리터럴 상수는 int 형 범위를 벗어나지만, long 형 범위를 넘어가지는 않는 상수입니다. C언어나 C++ 에서는 다음과 같이 선언하면 전혀 문제가 되지 않지만, 자바에서는 기본적으로 int 형으로 인식하기 때문에 에러가 발생합니다. 따라서, int 형 범위를 벗어나는 숫자를 다루고 싶다면 다음과 같이 숫자 끝에 'L' 또는 'l' 을 붙여서 long 형 정수로 봐달라고 표현해줘야 컴파일러가 제대로 인식을 할 수 있습니다.

long num = 99999999999L;

 자바는 byte형과 short형 정수의 표현 방법을 제공하지 않기 때문에 byte형과 short 형은 아래와 같이 그냥 int 형으로 초기화를 할 수 있습니다. 또, 연산을 byte 형이나 short형으로 진행하는 방법은 없습니다.

byte num = 2;
short num = 5;

 자바는 int 형 정수를 2진수, 8진수, 16진수로 표현할 수 있습니다. 숫자 앞에 2진수는 '0B' 또는 '0b'  , 8진수는 '0', 16진수는 '0x' 또는 '0X' 를 붙여서 표현할 수 있습니다.

int num = 0B11; // 2진수 11 -> 3
int num = 011; // 8진수 11 -> 9
int num2 = 0X11; // 16진수 11 -> 17

 또, 자바는 단위가 큰 수의 표현 및 인식에 도움을 주기 위해서 숫자 중간에 언더바를 넣는 것도 허용합니다.

int num = 999_999_999; // 999999999를 의미

실수형 리터럴(Literals)


 자바에서 실수형 숫자들은 모두 double 형으로 인식합니다. 따라서, float 형으로 표현하고 싶다면 숫자 뒤에 'f' 또는 'F'를 붙여서 표현해줘야 합니다.

float num = 3.005F; // float형
double num = 3.005; // double형

 따라서, 다음과 같은 표현은 에러가 발생합니다.

float num = 3.005; // 실수는 기본적으로 double 형으로 인식한다.

 

 

안녕하세요, 여행벌입니다.

이번 포스팅에서는 상수란 무엇인지 알아보겠습니다.


상수


■ 상수는 '값이 변하지 않는 수' 를 의미합니다. 자바에서는 한번 그 값이 정해지면 이후로는 변경이 불가능한 변수를 상수라고 얘기합니다.

■ 자바에서는 변수를 선언할 때 앞에 final 이라는 선언을 추가하면 그 변수는 '상수'가 됩니다.

package example1;

public class example1_1 {
	public static void main(String args[]) {
		final int SIZE =100;
		final char NAME = '홍';
		final int MAX_SIZE;
		MAX_SIZE = 150;
		System.out.println(MAX_SIZE);
	}
}

 같이 final 을 추가해 변수를 선언하면 '상수' 가 됩니다. 선언하면서 값을 초기화 해도 되고 아니면 선언하고 후에 값을 초기화해도됩니다. 하지만 한 번 값을 선언하면 바꿀 수 없습니다.ㅁㄴ

package example1;

public class example1_1 {
	public static void main(String args[]) {
		final int SIZE =100;
		SIZE = 150;
		System.out.println(SIZE);
	}
}

 

위의 코드는 한 번 값을 선언한 상수의 값을 바꾸려고 하기 때문에 에러가 발생합니다.


상수 이름 규칙


■ 상수의 이름은 모두 대문자로 짓습니다.

■ 이름이 둘 이상의 단어로 이루어진 경우 단어 사이에 언더바를 넣습니다.


이번 포스팅에서는 final 키워드를 이용해 상수를 선언하는 법에 대해서 다뤄보았습니다.

final 키워드는 다른 용도로도 많이 사용되는 키워드입니다.

그 부분에 대해서는 다른 포스팅에서 다뤄보겠습니다.


[ 알고리즘풀이 ]

규칙만 찾으면 구현은 간단한 문제입니다.

n = 1 [ 0 ]

n = 2 [ 0 0 1 ]

n = 3 [ 0 0 1 0 0 1 1 ]

n = 4 [ 0 0 1 0 0 1 1 0 0 0 1 1 0 1 1 ]

n = 5 [ 0 0 1 0 0 1 1 0 0 0 1 1 0 1 1 0 0 0 1 0 0 1 1 1 0 0 1 1 0 1 1 ]

n = k 일 때, 파란색 부분을 보시면 n = k - 1일 때와 동일한 것을 파악할 수 있습니다. 빨간색 부분도 자세히 보면 n = k - 1 일 때에서 검은색 부분인 '0' 만 '1'로 바꿔주면 나머지 부분은 동일한 것을 확인할 수 있습니다. 따라서, 파란색 부분을 의미하는 left 와 빨간색 부분을 의미하는 right 를 갱신해나가며 답을 구할 수 있습니다.

#include <string>
#include <vector>
#include <queue>
#include <iostream>

using namespace std;

vector<int> solution(int n) {
    vector<int> answer;

    string left = "0", right = "1";
    for(int i = 2; i <= n; i++){
        string ltmp = left + '0', rtmp = left + '1';
        ltmp = ltmp + right; rtmp = rtmp + right;
        left = ltmp; right = rtmp;
    }
    for(int i = 0; i < left.size(); i++){
        answer.push_back(left[i] - '0');
    }

    return answer;
}

 

문제 : https://www.acmicpc.net/problem/16637


[ 알고리즘풀이 ]

■ 우리는 (N / 2) 개의 연산과 (N / 2) + 1 개의 숫자로 이루어진 식을 입력받는다. 또, 1, 3, 5, 7 ⋯ 과 같이 홀수 인덱스는 연산, 짝수 인덱스는 숫자에 해당한다.

N / 2 개의 연산 중 어느 곳에 괄호를 칠지 Backtracking 을 통해 모든 경우에 대해서 식을 계산해본다.

( 이때, 괄호를 친 연산 바로 다음 연산은 괄호가 겹치므로 괄호를 check 하면 안된다. )

■ 식을 앞에서부터 순회하며 괄호 유무에 따라 식을 숫자 파트와 연산 파트로 나눠서 vector 에 저장한다.

- 숫자와 숫자 다음 칸인 연산에 괄호가 쳐져있다면 그 다음 숫자와 먼저 계산을 하고 계산한 값과 그 다음 연산을 vector에 저장한다.

- 그렇지 않다면, 해당 숫자과 연산을 각각 vector에 저장한다.

■ 저장된 숫자와 연산을 계산한다.

■ 답을 갱신한다.

답은 최대 9^10 으로 long long 으로 저장해줘야한다..!!!

#include<iostream>
#include<string>
#include<algorithm>
#include<vector>

using namespace std;

int N;
long long ans = -999999999999999;
string expression;
bool op[9] = {};

long long getResult(void) {
	vector<long long> v1;
	vector<char> v2;
	int i = 0;
	while(i < N){
		if (op[(i + 1) / 2]) {// 숫잔데 괄호쳐져있음.
			if (expression[i + 1] == '+')
				v1.push_back((expression[i] - '0') + (expression[i + 2] - '0'));
			else if (expression[i + 1] == '-')
				v1.push_back((expression[i] - '0') - (expression[i + 2] - '0'));
			else if (expression[i + 1] == '*')
				v1.push_back((expression[i] - '0') * (expression[i + 2] - '0'));

			if (i + 3 < N)
				v2.push_back(expression[i + 3]);
			i += 4;
		}
		else if (!op[(i + 1) / 2]){
			v1.push_back(expression[i] - '0');
			if(i + 1 < N)
				v2.push_back(expression[i + 1]);
			i += 2;
		}
	}
	long long sum = v1[0];
	for (int i = 1; i < v1.size(); i++) {
		if (v2[i - 1] == '+')
			sum += v1[i];
		else if (v2[i - 1] == '-')
			sum -= v1[i];
		else if (v2[i - 1] == '*')
			sum *= v1[i];
	}
	return sum;
}

void Backtracking(int start) {
	ans = max(ans, getResult());
	for (int i = start; i < N / 2; i++) {
		op[i] = 1;
		Backtracking(i + 2);
		op[i] = 0;
	}
	return;
}
int main(void) {
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);

	cin >> N >> expression;

	Backtracking(0);

	cout << ans;
}

 

+ Recent posts