728x90

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

 

1100번: 하얀 칸

체스판은 8*8크기이고, 검정 칸과 하얀 칸이 번갈아가면서 색칠되어 있다. 가장 왼쪽 위칸 (0,0)은 하얀색이다. 체스판의 상태가 주어졌을 때, 하얀 칸 위에 말이 몇 개 있는지 출력하는 프로그램을 작성하시오.

www.acmicpc.net

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;


int main() {
	char arr[8][8];
	for (int i = 0; i < 8; i++) {
		for (int j = 0; j < 8; j++) {
			cin >> arr[i][j];
		}
	}
	int count = 0;
	for (int i = 0; i < 8; i++) {
		for (int j = 0; j < 8; j++) {
			if ((i + j) % 2 == 0 && arr[i][j] == 'F') count++;
		}
	}
	cout << count;
	return 0;
}
728x90

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

[백준] 9465번 스티커  (0) 2020.02.17
[백준] 1431번 시리얼 번호  (0) 2020.02.15
[백준] 3474번 교수가 된 현우  (0) 2020.02.15
[백준] 10816번 숫자 카드 2  (0) 2020.02.13
[백준] 1920번 수 찾기  (0) 2020.02.13
728x90

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

 

3474번: 교수가 된 현우

문제 알고리즘의 킹갓제너럴엠퍼러마제스티충무공알고리즘마스터 현우가 교수로 취임하였다! 그러나 학생들에게 크나큰 기대를 품고 첫 수업에 들어갔던 현우는 아무도 외판원 순회 문제(Traveling Salesman Problem, TSP)를 풀지 못하는 것을 보고 낙심하였다. 그 와중에 학생 남규는 TSP를 완전탐색으로 풀려고 하였고, 현우는 그걸 보고 경악을 금치 못한다. 왜냐면 TSP를 완전탐색으로 풀려면 O(N!)의 시간이 소모되는데, 이는 경악을 금치 못

www.acmicpc.net

이렇게 제출했는데 시간초과가 났다.

#include <iostream>
#include <vector>
using namespace std;

int main() {
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	int n;
	cin >> n;
	vector<int> v(n);
	for (int i = 0; i < n; i++) {
		cin >> v[i];
	}
	int five[] = { 1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, 48828125, 244140625, 1220703125 };
	int index = 1;
	int vectorIndex = 0;
	int now = 0;
	int previous = 0;
	for (int i = 1; i <= 1000000000; i++) {
		int increase;
		for (int j = index; j >= 0; j--) {
			if (i % five[j] == 0) {
				increase = j;
				if (j == index)
					index++;
				break;
			}
		}
		now = previous+ increase;

		if (i == v[vectorIndex]) {
			cout << now << '\n';
			vectorIndex++;
			if (vectorIndex == n) break;
		}
		previous = now;
	}
	return 0;
}

대략 반복문 수행 횟수가 10000000 넘어가면 1초 넘는데 얘는 1000000000에 이중 for문이니까 당연히 시간초과가 난다.

 

이렇게 다시 풀었다.

#include <iostream>
#include <vector>
using namespace std;

int main() {
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	int n;
	cin >> n;
	for (int i = 0; i < n; i++) {
		int num;
		cin >> num;
		int count = 0;
		for (int j = 5; j <= num; j *= 5) {
			count += num / j;
		}
		cout << count << '\n';
	}
	return 0;
}
728x90

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

[백준] 1431번 시리얼 번호  (0) 2020.02.15
[백준] 1100번 하얀 칸  (0) 2020.02.15
[백준] 10816번 숫자 카드 2  (0) 2020.02.13
[백준] 1920번 수 찾기  (0) 2020.02.13
[백준] 2902번 KMP는 왜 KMP일까?  (0) 2020.02.12
728x90

C++로 코딩을 하다가 이진탐색을 할 필요가 있다면 직접 구현할 필요없이 <algorithm> 헤더에 정의되어 있는 binary_search() 함수를 사용하면 된다. C++에서 이진탐색을 어떻게 하는지 알아보자.

 

일단 이진탐색이라는 것은 데이터가 정렬되어 있다는 전제하에 가능하다.

정렬을 하려면 sort() 함수를 이용하면 된다.

정렬을 설명하기엔 너무 길어질 것 같으니 sort() 함수 사용법은 이전 포스팅을 참고하면 된다.(↓링크)

https://breakcoding.tistory.com/117?category=876361

 

[C++] vector (벡터) 정렬, 배열 정렬하기

정렬을 하려면 라이브러리의 sort() 함수를 쓰면 된다. 따라서 헤더파일을 포함해줘야 한다. sort() 함수의 첫번째 두번째 매개변수는 iterator, 즉 포인터이다. sort - C++ Reference cu..

breakcoding.tistory.com

binary_search 함수의 사용법은 간단하다.

http://www.cplusplus.com/reference/algorithm/binary_search/

 

binary_search - C++ Reference

function template std::binary_search default (1)template bool binary_search (ForwardIterator first, ForwardIterator last, const T& val); custom (2)template bool binary_search (ForwardIterator first, ForwardIterator last, const T& val, Compare c

www.cplusplus.com

binary_search() 함수의 첫 번째, 두 번째 인자는 내가 어디에서 찾고 싶은지 (배열이든 벡터든) 그 자료구조의 시작 주소끝나는 주소를 넣어주면 된다. 주의해야 할 것은 주소를 넣어줘야 한다는 것이다.

찾고 싶은 곳이 크기가 6인 arr라는 배열이라면 arr를 첫 번째 인자로, arr+6을 두 번째 인자로 넣어주면 된다.

찾고 싶은 곳이 v라는 벡터라면 v.begin()을 첫 번째 인자로, v.end()를 두 번째 인자로 넣어주면 된다.

세 번째 인자는 그 곳에 있는지 없는지 궁금한 내가 찾고 싶은 대상이다.

반환 타입은 bool 타입으로, 있으면 1(true), 없으면 0(false)를 반환한다.

 

크기가 10인 정렬된 배열 arr에 3이 있는지 없는지 알고 싶다면

bool isIn = binary_search(arr, arr + 10, 3);

정렬된 벡터 v에 3이 있는지 없는지 알고 싶다면

bool isIn = binray_search(v.begin(), v.end(), 3);

이렇게 해주면 된다.

arr 배열에 또는 v 벡터에 3이 있다면 isIn에는 true가 저장되고 3이 없다면 isIn에는 false가 저장된다.

 

#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;


int main() {
	int arr[] = { 3, 16, 7, 1, 20, 8, 3, 10, 25, 18 };
	sort(arr, arr + 6); //이진탐색 전에 반드시 정렬을 해줘야 한다.
	cout << "arr에 8이 있나요? " << boolalpha << binary_search(arr, arr + 6, 8) << endl;
	cout << "arr에 2가 있나요? " << boolalpha << binary_search(arr, arr + 6, 2) << endl;
	return 0;
}

8은 배열 v에 있으니 true를, 2는 배열 arr에 없으니 false를 반환하는 것을 볼 수 있다.

 

벡터도 마찬가지이다.

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <vector>
using namespace std;


int main() {
	vector<int> v = { 3, 16, 7, 1, 20, 8, 3, 10, 25, 18 };
	sort(v.begin(), v.end()); //이진탐색 전에 반드시 정렬을 해줘야 한다.
	cout << "arr에 8이 있나요? " << boolalpha << binary_search(v.begin(), v.end(), 8) << endl;
	cout << "arr에 2가 있나요? " << boolalpha << binary_search(v.begin(), v.end(), 2) << endl;
	return 0;
}

 

하지만 있는지 없는지 true, false로 반환을 해줄 뿐 어느 인덱스에 있는지는 binary_search 함수로는 알 수 없다.

그래서 사용하는 것이 upper_bound, lower_bound 함수이다.

upper_bound와 lower_bound의 첫 번째, 두 번째 인자는 내가 찾고 싶은 범위를 주소로 지정해주면 된다. 꼭 배열 전체, 벡터 전체일 필요는 없다. 해당 범위를 지정해주고 그 안에 있는지만 찾고 싶으면 그렇게 지정해주면 된다. binary_search 함수의 인자와 똑같다.

세 번째 인자도 binary_search의 세 번째 인자처럼 몇 개 있는지 알고 싶은 그 대상을 적어주면 된다.

 

lower_bound 함수는 내가 찾고자 하는 그 대상이 저장된 인덱스 중 가장 작은 인덱스를 반환한다.

upper_bound 함수는 내가 찾고자 하는 그 대상이 저장된 인덱스 중 가장 큰 인덱스+1을 반환한다.

 

예를 들어 정렬된 arr 배열에 다음과 같이 저장되어 있었다고 하자.

1 3 4 4 7 10 10 10 13 17

lower_bound(arr, arr + 10, 10)을 한다면 10이 처음 등장하는 인덱스인 인덱스 5의 주소를 반환한다.

upper_bound(arr, arr + 10, 10)을 한다면 10이 마지막으로 등장하는 인덱스+1인 인덱스 8의 주소을 반환한다.

iterator(메모리 주소)를 반환하기 때문에 몇 번째 인덱스인지 알아보고 싶으면 배열이나 벡터의 시작주소를 빼보면 된다.

 

일단 lower_bound와 upper_bound 함수의 반환값을 알아보기 위해서 그냥 출력해보면

#include <iostream>
#include <algorithm>
using namespace std;


int main() {
	int arr[] = { 1, 3, 4, 4, 7, 10, 10, 10, 13, 17 };
	sort(arr, arr + 10);
	cout << "lower_bound: " << lower_bound(arr, arr + 10, 10) << endl;
	cout << "upper_bound: " << upper_bound(arr, arr + 10, 10) << endl;
	return 0;
}

이렇게 주소를 반환하는 것을 알 수 있다. 004FFBE4에서 004FFBD4를 빼면 12이다. arr가 int 타입이므로 인덱스 5의 주소와 8의 주소는 3 x 4byte 총 12바이트 차이나는 것이다.

 

이렇게 주소 말고 인덱스로 보고 싶다면 이렇게 시작주소를 빼주면 된다. 

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;


int main() {
	vector<int> v = { 1, 3, 4, 4, 7, 10, 10, 10, 13, 17 };
	sort(v.begin(), v.end());
	cout << "lower_bound: " << lower_bound(v.begin(), v.end(), 10) - v.begin() << endl;
	cout << "upper_bound: " << upper_bound(v.begin(), v.end(), 10) - v.begin() << endl;
	return 0;
}

#include <iostream>
#include <algorithm>
using namespace std;


int main() {
	int arr[] = { 1, 3, 4, 4, 7, 10, 10, 10, 13, 17 };
	sort(arr, arr + 10);
	cout << "lower_bound: " << lower_bound(arr, arr + 10, 10) - arr << endl;
	cout << "upper_bound: " << upper_bound(arr, arr + 10, 10) - arr << endl;
	return 0;
}

이렇게 10의 시작인덱스, 10의 마지막 인덱스+1을 출력하는 것을 볼 수 있다. 그 인덱스에 뭐가 들어있는지 알아보고 싶으면 역참조 연산자 *로 데이터에 접근해서 출력해보면 된다. 10의 마지막 인덱스 한 칸 뒤에는 13이 저장되어 있으니 13이 출력될 것을 알 수 있다.

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;


int main() {
	int arr[] = { 1, 3, 4, 4, 7, 10, 10, 10, 13, 17 };
	sort(arr, arr + 10);
	cout << "lower_bound: " << *lower_bound(arr, arr + 10, 10) << endl;
	cout << "upper_bound: " << *upper_bound(arr, arr + 10, 10) << endl;
	return 0;
}

역참조 연산자가 익숙치 않다면 이전 포스팅을 참고하면 도움이 될 것이다. (↓링크)

https://breakcoding.tistory.com/81

 

[C++] 포인터

포인터를 어려워하는 분들이 많은 것 같다. 물론 나도 겁먹었었다. 하지만 전혀 어렵지 않다는 것을 알게 되었고 다른 사람들에게도 포인터가 어렵지 않다는 것을 알려주고 싶다. 일반적으로 변수는 정수, 실수,..

breakcoding.tistory.com

10이 arr에 몇 개가 있는지 알고 싶다면 upper_bound에서 lower_bound를 빼보면 된다.

#include <iostream>
#include <algorithm>
using namespace std;

int main() {
	int arr[] = { 1, 3, 4, 4, 7, 10, 10, 10, 13, 17 };
	sort(arr, arr + 10);
	cout << "arr에 10은 " << upper_bound(arr, arr + 10, 10) - lower_bound(arr, arr + 10, 10) << "개가 있다" << endl;
	return 0;
}

728x90
728x90

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

 

10816번: 숫자 카드 2

첫째 줄에 상근이가 가지고 있는 숫자 카드의 개수 N(1 ≤ N ≤ 500,000)이가 주어진다. 둘째 줄에는 숫자 카드에 적혀있는 정수가 주어진다. 숫자 카드에 적혀있는 수는 -10,000,000보다 크거나 같고, 10,000,000보다 작거나 같다. 셋째 줄에는 M(1 ≤ M ≤ 500,000)이 주어진다. 넷째 줄에는 상근이가 몇 개 가지고 있는 숫자 카드인지 구해야 할 M개의 정수가 주어지며, 이 수는 공백으로 구분되어져 있다. 이수도 -10,00

www.acmicpc.net

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;


int main() {
	cin.tie(NULL);
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	vector<int> sanggeun(n);
	map<int, int> ma;
	for (int i = 0; i < n; i++) {
		cin >> sanggeun[i];
		if (ma.find(sanggeun[i]) != ma.end()) ma[sanggeun[i]]++;
		else ma[sanggeun[i]] = 1;
	}
	sort(sanggeun.begin(), sanggeun.end());
	int m;
	cin >> m;
	for (int i = 0; i < m; i++) {
		int target;
		cin >> target;
		cout << upper_bound(sanggeun.begin(), sanggeun.end(), target) - lower_bound(sanggeun.begin(), sanggeun.end(), target) << " ";
	}
	return 0;
}
728x90
728x90

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

 

1920번: 수 찾기

첫째 줄에 자연수 N(1≤N≤100,000)이 주어진다. 다음 줄에는 N개의 정수 A[1], A[2], …, A[N]이 주어진다. 다음 줄에는 M(1≤M≤100,000)이 주어진다. 다음 줄에는 M개의 수들이 주어지는데, 이 수들이 A안에 존재하는지 알아내면 된다. 모든 정수들의 범위는 int 로 한다.

www.acmicpc.net

이진탐색으로 풀어야 풀리는 문제이다.

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;


int main() {
	cin.tie(NULL);
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	vector<int> v(n);
	for (int i = 0; i < n; i++) {
		cin >> v[i];
	}
	sort(v.begin(), v.end());
	int m;
	cin >> m;
	for (int i = 0; i < m; i++) {
		int target;
		cin >> target;
		int start = 0; 
		int end = v.size() - 1;
		int key = -1;
		while (start <= end) {
			if (v[(start + end) / 2] == target) {
				key = (start + end) / 2;
				break;
			}
			else if (v[(start + end) / 2] > target) {
				end = (start + end) / 2 - 1;
			}
			else if (v[(start + end) / 2] < target) {
				start = (start + end) / 2 + 1;
			}
		}
		if (key == -1) cout << 0 << '\n';
		else cout << 1 << '\n';
	}
	return 0;
}

이진탐색으로 풀었더니 60ms로 성공

 

혹시나 하고 C++에 있는 find() 함수를 사용해서 풀어봤다.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	int n, m;
	cin >> n;
	vector<int> arr(n);
	for (int i = 0; i < n; i++) {
		cin >> arr[i];
	}
	cin >> m;
	for (int i = 0; i < m; i++) {
		int temp;
		cin >> temp;
		vector<int>::iterator iter;
		iter = find(arr.begin(), arr.end(), temp);
		if (iter != arr.end()) {
			cout << 1 << '\n';
		}
		else cout << 0 << '\n';
	}
	return 0;
}

무려 1796ms로 성공. 있는지 없는지 한 번만 찾아볼거면 굳이 정렬하는 시간을 들여서까지 이진탐색을 할 필요는 없는데 이 경우는 한 배열에서 어떤 숫자가 있는지 없는지 여러번 찾아볼 것이기 때문에 이진탐색이 훨씬 효율적이다. 정렬을 한 번만 해주면 그 후로 매우 빠르게 찾을 수 있다.

728x90
728x90

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

 

2902번: KMP는 왜 KMP일까?

문제 KMP 알고리즘이 KMP인 이유는 이를 만든 사람의 성이 Knuth, Morris, Prett이기 때문이다. 이렇게 알고리즘에는 발견한 사람의 성을 따서 이름을 붙이는 경우가 많다. 또 다른 예로, 유명한 비대칭 암호화 알고리즘 RSA는 이를 만든 사람의 이름이 Rivest, Shamir, Adleman이다. 사람들은 이렇게 사람 성이 들어간 알고리즘을 두 가지 형태로 부른다. 첫 번째는 성을 모두 쓰고, 이를 하이픈(-)으로 이어 붙인 것이다. 예

www.acmicpc.net

#include <iostream>
#include <string>
using namespace std;


int main() {
	string s; 
	cin >> s;
	cout << s[0];
	for (int i = 1; i < s.size(); i++) {
		if (s[i] >= 65 && s[i] < 91) cout << s[i];
	}
	return 0;
}
728x90
728x90

이 글에 이어지는 글이다. (↓링크)

 

[Java] 람다식(lambda expression)과 메소드 참조(method reference)

C/C++에는 함수포인터라는 개념이 있어 함수를 다른 함수로 전달하고 싶을 때에는 함수 포인터를 사용하면 된다. 그런데 자바는 C/C++보다 더 객체지향적인 언어이기 때문에 메소드(C/C++로 따지면 함수)는 무조건..

breakcoding.tistory.com

람다식은 불필요한 코드를 생략하고 메소드 내부 코드만 작성해서 간단하게 인터페이스 객체를 생성하는 방법이었다. 

하지만 람다식도 불필요한 부분들이 있다. 다음 코드를 보자.

interface ReturnNumber {
    void function(int n);
}
public class LambdaTest {
    public static void main(String[] args) {
        printNumber(x -> System.out.println(x), 10); //받은 수를 그대로 반환하는 ReturnNumber 객체를 만들어서 넘겨줌
    }
    static void printNumber(ReturnNumber returnNumber, int num) {
        returnNumber.function(num);
    }
}

이 코드를 보면 x -> System.out.println(x)라는 람다식으로 ReturnNumber 객체를 만들어서 메소드의 인자로 넘겨줬다.

하지만 이 람다식은 너무 간단하다. 받은 것을 그대로 출력하라는 것인데 x를 두 번이나 썼다. 이 x를 불필요한 부분이라고 생각해서 이런 간단한 코드들은 메소드참조를 써서 더욱 더 간결하게 만들 수 있게 했다.

interface ReturnNumber {
    void function(int n);
}
public class LambdaTest {
    public static void main(String[] args) {
        printNumber(System.out::println, 10); //받은 수를를 그대로 반환하는 ChangeNumber 객체를 만들어서 넘겨줌
    }
    static void printNumber(ReturnNumber returnNumber, int num) {
        returnNumber.function(num);
    }
}

이렇게 System.out::println만 해주면 인자를 받아서 그 인자를 출력하도록 하는 메소드를 구현한 것이다.

람다식인 x -> System.out.println(x)보다 훨씬은 아니지만 메소드 참조를 사용하니 조금 더 간결해졌다.

 

다음 코드를 보자.

public class LambdaTest {
    public static void main(String[] args) {
        String[] names = {"Bill", "jane", "Anne", "billy", "Tom", "jake", "amily", "Susan"};
        Arrays.sort(names);
        for(String s : names)
            System.out.print(s + " ");
    }
}

대소문자가 구별되어 정렬됨

이렇게 Arrays.sort() 메소드를 사용해서 배열을 정렬하면 자동으로 오름차순 정렬이 되는데 문자열의 경우 유니코드의 값을 기준으로 오름차순 정렬을 하기 때문에 소문자는 무조건 대문자보다 뒤에 오게 된다.

 

만약 이것이 싫다면 내가 원하는 정렬기준으로 compare​(T o1, T o2) 메소드를 구현한 Comparator 인터페이스를 객체를 Arrays.sort() 메소드의 두 번째 인자로 넣어주면 된다. 그런데 String 클래스에 대소문자 구별없이  이미 만들어져있는 메소드가 있다. 그 메소드를 부르면 Comparator 객체를 반환하는 것은 아니고 그 메소드의 반환값을 compareTo(T o1, T o2) 메소드의 반환값으로 구현만 해주면 된다. String 클래스에 있는 compareToIgnoreCase() 메소드이다.

https://docs.oracle.com/javase/10/docs/api/java/lang/String.html

 

String (Java SE 10 & JDK 10 )

Compares two strings lexicographically. The comparison is based on the Unicode value of each character in the strings. The character sequence represented by this String object is compared lexicographically to the character sequence represented by the argum

docs.oracle.com

compareTo() 메소드는 Comparator 인터페이스의 유일한 추상메소드이기 때문에 람다식 사용이 가능하다.

(람다식은 인터페이스에 추상메소드가 딱 1개만 있을 때 사용 가능하다)

https://docs.oracle.com/javase/10/docs/api/java/util/Comparator.html

 

Comparator (Java SE 10 & JDK 10 )

Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. The implementor must ensure that sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and

docs.oracle.com

import java.util.Arrays;

public class LambdaTest {
    public static void main(String[] args) {
        String[] names = {"Bill", "jane", "Anne", "billy", "Tom", "jake", "amily", "Susan"};
        Arrays.sort(names, (a, b) -> a.compareToIgnoreCase(b));
        for(String s : names)
            System.out.print(s + " ");
    }
}

이렇게 람다식으로 Arrays.sort() 메소드의 두 번째 인자에 대소문자를 구분 안 하는 Comparator 객체를 넣어주면

 

이렇게 대소문자 구별 없이 정렬된 것을 볼 수 있다.

하지만 (a, b) -> a.compareToIgnoreCase(b)에서 a, b가 두 번씩 사용되어 불필요한 코드라고 생각해서 이것도 메소드 참조로 표현할 수 있도록 했다.

import java.util.Arrays;

public class LambdaTest {
    public static void main(String[] args) {
        String[] names = {"Bill", "jane", "Anne", "billy", "Tom", "jake", "amily", "Susan"};
        Arrays.sort(names, String::compareToIgnoreCase);
        for(String s : names)
            System.out.print(s + " ");
    }
}

String::compareToIgnoreCase 이렇게 메소드 참조를 사용하면 코드가 좀 더 간결해졌다.

이 코드의 실행결과는 위 코드의 실행결과와 정확히 똑같다.

 

그리고 스트림에서 특히 람다식과 메소드 참조가 정말 유용하게 사용되는데

list.removeIf(x -> Objects.isNull(x));

이런 코드도 메소드 참조를 이용하면

list.removeIf(Objects::isNull);

이렇게 더 간결하게 줄일 수 있다.

 

list.forEach(x -> System.out.println(x));

이런 코드도 메소드 참조를 이용하면

list.forEach(System.out::println);

이렇게 줄일 수 있다.

 

메소드 참조의 규칙을 정리하자면 다음과 같다.

  람다식 메소드 참조
static 메소드 a ->클래스이름.메소드(a) 클래스이름::메소드이름
인스턴스 메소드 (a, b) -> a.메소드(b) 클래스이름::메소드이름
(a) -> 객체.메소드(a) 객체::메소드이름
생성자 (a) -> new 생성자(a) 생성자이름::new
배열 생성자 (a) -> new 타입[a] 타입::new

첫 번째 예제 코드에서 배운 a -> System.out.println(a)를 System.out::println으로 줄이는 것은 이 표에서 3번째 즉, 인스턴스 메소드에서 (a) -> 객체.메소드(a)를 객체::메소드이름으로 바꾸는 것에 해당한다. (System.out은 표준 출력을 담당하는 객체이다.)

두 번째 예제 코드에서 배운 a.compareToIgnoreCase(b)를 String::compareToIgnoreCase로 바꾸는 것은 이 표에서 두 번째 즉, (a, b) -> a.메소드(b) 에서 클래스이름::메소드이름으로 바꾸는 것에 해당한다.

 

생성자와 배열 생성자를 메소드 참조로 바꾸는 예를 살펴보자. 스트림을 배우지 않았다면 낯설 수 있지만 그래도 메소드 참조를 어떻게 사용하는지 감이 올 것이다.

import java.util.ArrayList;
import java.util.Arrays;

public class LambdaTest {
    public static void main(String[] args) {
        ArrayList<String> names = new ArrayList<>();
        names.add("Peter");
        names.add("Paul");
        names.add("Mary");
        Employee[] employees = names.stream().map(Employee::new).toArray(Employee[]::new);
        System.out.println(Arrays.toString(employees));
    }
}
class Employee {
    String name;

    public Employee(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }
}

String 타입의 ArrayList names를 메소드 참조를 이용해서 배열로 바꿔주었다. Employee 클래스의 생성자와 Employee[] 배열 생성자를 메소드 참조로 표현했다.

조금 어려울 수도 있는데 그러면 그냥 람다식을 사용하면 되고 사실 메소드 참조는 아까 봤던 예제 정도가 자주 쓰인다.

728x90
728x90

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

 

4659번: 비밀번호 발음하기

문제 좋은 패스워드를 만드는것은 어려운 일이다. 대부분의 사용자들은 buddy처럼 발음하기 좋고 기억하기 쉬운 패스워드를 원하나, 이런 패스워드들은 보안의 문제가 발생한다. 어떤 사이트들은 xvtpzyo 같은 비밀번호를 무작위로 부여해 주기도 하지만, 사용자들은 이를 외우는데 어려움을 느끼고 심지어는 포스트잇에 적어 컴퓨터에 붙여놓는다. 가장 이상적인 해결법은 '발음이 가능한' 패스워드를 만드는 것으로 적당히 외우기 쉬우면서도 안전하게 계정을 지킬 수 있

www.acmicpc.net

#include <iostream>
#include <string>
#include <vector>
using namespace std;


int main() {
	while (true) {
		string s;
		cin >> s;
		if (s == "end") break;
		bool flag = false;
		int countVowel = 0;
		vector<bool> isVowel(s.size());
		
		if (s[0] == 'a' || s[0] == 'e' || s[0] == 'i' || s[0] == 'o' || s[0] == 'u') {
			countVowel++;
			isVowel[0] = true;
		}
		for (int i = 1; i < s.size(); i++) {
			if (s[i] != 'e' && s[i] != 'o' && s[i - 1] == s[i]) {
				flag = true;
				break;
			}
			if (s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u') {
				countVowel++;
				isVowel[i] = true;
			}
		}
		if (flag || countVowel == 0) {
			cout << '<' << s << "> is not acceptable.\n";
			continue;
		}
		for (int i = 2; i < s.size(); i++) {
			if (isVowel[i - 2] == isVowel[i - 1] && isVowel[i - 1] == isVowel[i]) {
				flag = true;
				break;
			}
		}
		if(flag) cout << '<' << s << "> is not acceptable.\n";
		else cout << '<' << s << "> is acceptable.\n";
	}
	return 0;
}
728x90
728x90

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

 

4690번: 완전 세제곱

문제 페르마의 마지막 정리는, a, b, c가 0이 아닌 정수이고, n이 2보다 큰 자연수 일 때, an = bn + cn을 만족하는 자연수 a, b, c가 존재하지 않는다는 정리이다. 이 정리는 아직 증명되지 않았다. 하지만, 완전 세제곱 방정식 a3 = b3 + c3 + d3을 만족하는 1보다 큰 자연수를 찾는 것은 어렵지 않다. (123 = 63 + 83 + 103) 이러한 완전 세제곱 방정식과 a ≤ 100을 만족하는 {a, b, c, d}쌍을 모

www.acmicpc.net

#include <iostream>
#include <cmath>
using namespace std;


int main() {
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	for (int a = 2; a <= 100; a++) {
		for (int b = 2; b < a; b++) {
			for (int c = b; c < a; c++) {
				for (int d = c; d < a; d++) {
					if (pow(a, 3) == pow(b, 3) + pow(c, 3) + pow(d, 3)) {
						cout << "Cube = " << a << ", Triple = (" << b << "," << c << "," << d << ")\n";

					}
				}
			}
		}
	}
	return 0;
}
728x90
728x90

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

 

1592번: 영식이와 친구들

일단 1번이 공을 잡는다. 1번은 공을 한 번 잡았기 때문에, 공을 3번에게 던진다. 3번은 공을 한 번 잡았기 때문에, 공을 5번에게 던진다. 5번은 2번에게 던지고, 2번은 4번에게 던진다. 4번은 1번에게 던진다. 1번은 이제 공을 두 번 잡았기 때문에, 공을 4번에게 던진다. 4번은 2번에게 던지고, 2번은 5번에게 던지고, 5번은 3번에게 던지고, 마지막으로 3번은 1번에게 던진다. 1번은 이제 공을 세 번 잡았기 때문에, 게임은 끝난다.

www.acmicpc.net

#include <iostream>
#include <tuple>
#include <vector>
#include <map>
#include <queue>
using namespace std;


int main() {
	int numOfPeople, m, l;
	cin >> numOfPeople >> m >> l;
	vector<int> count(numOfPeople);
	int currentPerson = 0;
	count[currentPerson] = 1;
	int ballTossCount = 0;
	while (true) {
		ballTossCount++;
		if (count[0] % 2 == 0) {
			currentPerson = (currentPerson - l + numOfPeople) % numOfPeople;
		}
		else {
			currentPerson = (currentPerson + l) % numOfPeople;
		}
		count[currentPerson]++;
		if (count[currentPerson] == m) break;
	}
	cout << ballTossCount;
	return 0;
}
728x90

+ Recent posts