프로그래머스 기본 포맷
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String a = sc.next();
int b = sc.nextInt();
double c = sc.nextDouble();
// 개행 O
System.out.println(a);
// 개행 X
System.out.print(a);
}
}
문자열 반복해서 출력하기
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.next();
int n = sc.nextInt();
System.out.println(str.repeat(n));
}
}
● String.repeat(int n)
- ex. "str".repeat(5) ▶ "strstrstrstrstr"
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.next();
int n = sc.nextInt();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
sb.append(str);
}
String s = sb.toString();
System.out.println(s);
}
}
● String vs StringBuffer, StringBuilder
- String 객체
-- 한번 값이 할당되면 그 공간은 변하지 않음
-- 불변성 (Immutable)
- StringBuffer 객체 / StringBuilder 객체
-- 한번 값이 할당되더라도 한번 더 다른 값이 할당되면 할당된 공간이 변함
-- 가변성 (Mutable)
String str = "String";
StringBuilder sb = new StringBuilder();
StringBuffer sbf = new StringBuffer();
sb.append("StringBuilder");
sbf.append("StringBuffer");
// 연산 전 객체들의 주소
System.out.println("String 객체의 주소 : "+str.hashCode());
System.out.println("StringBuilder 객체의 주소 : "+sb.hashCode());
System.out.println("StringBuffer 객체의 주소 : "+sbf.hashCode());
str += "Test";
sb.append("Test");
sbf.append("Test");
System.out.println("=============================");
// 연산 후 객체들의 주소
System.out.println("String 객체의 주소 : "+str.hashCode());
System.out.println("StringBuilder 객체의 주소 : "+sb.hashCode());
System.out.println("StringBuffer 객체의 주소 : "+sbf.hashCode());
- String 객체의 주소는 변경 O
- StringBuilder와 StringBuffer 객체의 주소는 변경 X
● String
String str = "hello"; // String str = new String("hello");
str = str + " world"; // [ hello world ]
- hello 값을 가지고 있던 str 객체에 world 문자열을 더해 hello world 로 변경됨
- 그러나 기존에 hello 값이 들어가 있던 객체 주소와 hello world 값이 들어가 있는 동일한 객체 주소는 서로 다름
-- 이는 처음에는 hello 값이 들어가 있는 메모리 영역을 가리키다가, hello world 값이 들어있는 메모리 영역을 가리키도록 변경된 것임
-- 처음 가리키던 hello 값에 대한 메모리 영역은 Garbage 로 남아있다가 GC (Carbage Collection) 에 의해 정리됨
- String 클래스는 불변하기 때문에, 문자열을 연산하는 시점에 새로운 String 인스턴스가 메모리에 할당되는 것
-- 변하지 않는 문자열을 자주 읽어 들일 때 사용하면 좋은 성능을 기대할 수 있음
-- 그러나 문자열 추가, 수정, 삭제 등의 연산이 자주 일어나는 로직에서 String 클래스를 사용하면 힙 (Heap) 메모리에 많은 Garbage 가 생성되어 힙 메모리 부족으로 어플리케이션 성능에 큰 영향이 있을 수 있음
● String Constant Pool
- String 변수에 값을 할당하는 방법은 2가지
-- 리터럴 변수를 대입하는 방법
-- new 키워드를 사용하는 방법
String strA = "abc";
String strB = new String("abc");
String strC = "abc";
String strD = new String("abc");
System.out.println(strA == strB); // false
System.out.println(strA == strC); // true
System.out.println(strB == strD); // false
- 모두 "abc" 라는 문자열을 갖는데 주소비교의 결과가 상이함
-- 그 이유는 String 타입 값 할당 방식에 따른 저장 방식이 다르기 때문
-- String 을 리터럴 값으로 할당하는 경우엔 Heap 메모리 영역 안의 특별한 메모리 공간인 String constant pool 에 저장됨
-- 만약 String constant pool 에 존재하는 리터럴 값을 사용하게 된다면 새롭게 리터럴 값을 만들어 String constant pool 에 저장하는 것이 아닌, 현재 존재하는 값을 사용하게 됨
-- 이런 이유로 strA == strC 의 실행결과는 true
- new 키워드로 값을 할당하는 경우
-- 일반적인 객체와 동일하게 Heap 영역에 동적으로 메모리 공간이 할당되게 됨
-- 마찬가지로 같은 문자열이더라도 new 키워드를 한번 더 사용하게 되면 같은 값이지만 다른 메모리 공간 (Heap 영역 안) 을 참조하게 됨
-- 이런 이유로 strB == strD 의 실행결과는 true
● StringBuffer / StringBuilder
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, Comparable<StringBuilder>, CharSequence
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, Comparable<StringBuffer>, CharSequence
- 두 클래스 모두 AbstractStringBuilder 라는 추상 클래스를 상속받아 구현되어 있음
- AbstractStringBuilder 추상클래스의 멤버 변수엔 다음 2가지 변수가 존재함
-- value : 문자열의 값을 저장하는 byte 형 배열
-- count : 현재 문자열 크기의 값을 가지는 int 형 변수
- StringBuilder 와 StringBuffer 클래스의 문자열을 수정하고 싶으면 append() 메서드를 사용
-- 문자열을 추가하게 되면 추가할 문자열의 크기 (길이) 만큼 현재의 문자열을 저장하는 배열의 공간을 늘려주고, 늘려준 공간에 추가할 문자열을 넣어주는 방식으로 되어 있음
-- 이런 내부동작을 통해 값이 변경되더라도 같은 주소공간을 참조하게 되는 것이며, 값이 변경되는 가변성을 띄게 된다
public AbstractStringBuilder append(String str) {
if (str == null) {
return appendNull();
}
int len = str.length();
ensureCapacityInternal(count + len);
putStringAt(count, str);
count += len;
return this;
}
- 두 클래스의 기능은 동일하지만 동기화 (Synchronization) 에서의 차이점이 있음
-- StringBuilder 는 동기화 지원 X
-- StringBuffer 는 동기화 지원 O
- 그 이유는 StringBuffer 는 메서드에서 synchronized 키워드를 사용하기 때문임
-- java 에서 synchronized 키워드는 여러 개의 스레드가 한 개의 자원에 접근하려고 할 때, 현재 데이터를 사용하고 있는 스레드를 제외하고 나머지 스레드들이 데이터에 접근할 수 없도록 막는 역할을 수행
- ex. 멀티 스레드 환경에서 A 스레드와 B 스레드 모두 같은 StringBuffer 클래스의 객체 sb 의 append() 메서드를 사용하려고 하면, 다음과 같은 절차를 수행하게 됨
STEP 1. A 스레드 : sb 의 append() 동기화 블록에 접근 및 실행
STEP 2. B 스레드 : A 스레드의 sb 의 append() 동기화 블록에 들어가지 못하고 block 상태가 됨
STEP 3. A 스레드 : sb 의 append() 동기화 블록에서 탈출
STEP 4. B 스레드 : block 에서 running 상태가 되며 sb 의 append() 동기화 블록에 접근 및 실행
● String 을 사용해야 할 때
- 변하지 않는 문자열을 자주 사용할 경우 String 타입을 사용하는 것이 성능면에서 유리
● StringBuilder 를 사용해야 할 때
- 동기화 지원 X
- 속도면에서는 StringBuffer 보다 성능 좋음
- 단일 스레드 환경과 문자열의 추가, 수정, 삭제 등이 빈번히 발생하는 경우 StringBuilder 를 사용하는 것이 성능면에서 유리
● StringBuffer 를 사용해야 할 때
- 동기화 지원 O : 멀티 스레드 환경에서도 안전하게 동작 가능
- 멀티 스레드 환경과 문자열의 추가, 수정, 삭제 등이 빈번히 발생하는 경우 StringBuffer 를 사용하는 것이 성능면에서 유리
대소문자 바꿔서 출력하기
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String a = sc.next();
String result = "";
for (int i = 0; i < a.length(); i++) {
char c = a.charAt(i);
if (Character.isLowerCase(c)) {
result += Character.toUpperCase(c);
} else {
result += Character.toLowerCase(c);
}
}
System.out.println(result);
}
}
● Character.isUpperCase(char c)
- 'A' ~ 'Z' : true
● Character.isLowerCase(char c)
- 'a' ~ 'z' : true
● Character.isDigit(char c)
- '0' ~ '1' : true
● Character.toUpperCase(char c)
- 대문자로 변경
● Character.toLowerCase(char c)
- 소문자로 변경
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String a = sc.next();
for (int i = 0; i < a.length(); i++) {
char c = a.charAt(i);
if (Character.isUpperCase(c)) {
System.out.print((char)(c + 32));
} else {
System.out.print((char)(c - 32));
}
}
}
}
● 아스키넘버 사용
- 대문자 : 65 ~ 90
- 소문자 : 97 ~ 122
- 소문자 - 32 = 대문자
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String a = sc.next();
String answer = "";
for (int x : a.toCharArray()) {
if (x >= 97 && x <= 122) answer += (char)(x - 32);
else answer += (char)(x + 32);
}
System.out.print(answer);
}
}
● String.toCharArray()
- String 을 char 형 배열로 바꿈
String s1 = "Hello World";
char[] charArr = s1.toCharArray();
● char 형 배열을 합쳐서 하나의 String 으로 변경 가능
// how to use method
String s2 = new String(charArr);
특수문자 출력하기
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
System.out.println("!@#$%^&*(\\'\"<>?:;");
}
}
● 이스케이프 문자 정리
덧셈식 출력하기
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
int b = sc.nextInt();
System.out.printf("%d + %d = %d", a, b, a + b);
}
}
● printf()
- 내가 원하는 데이터 형식으로 출력
- 지시자
-- %b : 불리언 (boolean) 형식으로 출력
-- %d : 10 진수 형식으로 출력
-- %o : 8 진수 형식으로 출력
-- %x, %X : 16 진수 형식으로 출력 (%x : 소문자, %X : 대문자)
-- %f : 부동 소수점 형식으로 출력
-- %e, %E : 지수 형식으로 출력
-- %c : 문자 형식으로 출력
-- %s : 문자열 형식으로 출력
홀짝 구분하기
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
System.out.print(n + " is " + (n % 2 == 0 ? "even" : "odd"));
}
}
문자열 겹쳐쓰기
class Solution {
public String solution(String my_string, String overwrite_string, int s) {
String answer = "";
answer += my_string.substring(0, s);
answer += overwrite_string;
answer += my_string.substring(s+overwrite_string.length(), my_string.length());
return answer;
}
}
● 인덱스 위치 참조
class Solution {
public String solution(String my_string, String overwrite_string, int s) {
StringBuilder sb = new StringBuilder(my_string);
sb.replace(s, s + overwrite_string.length(), overwrite_string);
return sb.toString();
}
}
● StringBuilder 메소드
- public StringBuilder append(다양한 매개변수)
-- 문자열 추가
- public StringBuilder delete(int start, int end)
-- 문자열 삭제
- public StringBuilder insert(int offset, String str)
-- 문자열을 원하는 위치에 삽입
- public StringBuilder replace(int start, int end, String str)
-- 원하는 부분을 다른 문자열로 대체
- public StringBuilder reverse()
-- 문자열 뒤집기
- public String substring(int start, int end)
-- StringBuilder 인스턴스에 저장된 문자열의 부분 문자열을 String 인스턴스로 반환
-- 반환형이 String 인 것에 주의
문자열 섞기
class Solution {
public String solution(String str1, String str2) {
char[] chars1 = str1.toCharArray();
char[] chars2 = str2.toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < chars1.length; i++) {
sb.append(chars1[i]).append(chars2[i]);
}
return sb.toString();
}
}
● StringBuilder 클래스 활용
import java.util.stream.Collectors;
import java.util.stream.IntStream;
class Solution {
public String solution(String str1, String str2) {
return IntStream.range(0, str1.length())
.mapToObj(i -> Character.toString(str1.charAt(i)) + str2.charAt(i))
.collect(Collectors.joining());
}
}
● IntStream 사용법
- IntStream 은 기본 정수 요소의 열을 만들거나 병렬 집계 처리를 지원함
- 반복문 없이도 배열이나 컬렉션의 데이터를 처리할 수 있음
import java.util.stream.IntStream;
● range 와 rangeClosed
- 주어진 범위 내 순차적인 정수 스트림을 반환
- range 는 마지막 정수를 포함 X
- rangeClosed 는 마지막 정수를 포함 O
IntStream.range(1, 5)
.forEach(System.out::print); // 출력: 1234
IntStream.rangeClosed(1, 5)
.forEach(System.out::print); // 출력: 12345
● of
- 지정된 값을 포함하는 순차적인 정수 스트림을 반환
IntStream.of(1, 2, 3, 4, 5)
.forEach(System.out::print); // 출력: 12345
● map, filter
- map : 주어진 함수를 스트림의 각 요소에 적용한 결과로 구성된 스트림을 반환
- filter : 주어진 술어와 일치하는 요소만 포함하는 스트림을 반환
IntStream.rangeClosed(1, 5)
.map(n -> n * n)
.filter(n -> n % 2 == 0)
.forEach(System.out::println); // 출력: 4, 16
● sum, average, max, min
- sum : 각각 스트림의 요소의 합계 반환
- average : 각각 스트림의 요소의 평균 반환
- max : 각각 스트림의 요소의 최대값 반환
- min : 각각 스트림의 요소의 최소값 반환
int sum = IntStream.rangeClosed(1, 5)
.sum();
double avg = IntStream.rangeClosed(1, 5)
.average()
.getAsDouble();
int max = IntStream.rangeClosed(1, 5)
.max()
.getAsInt();
● anyMatch
- 스트림의 요소 중 어느 하나라도 주어진 술어를 만족하면 true 를 반환
boolean anyMatch = IntStream.of(1, 2, 3, 4, 5)
.anyMatch(n -> n == 3);
System.out.println(anyMatch); // 출력: true
● Java Stream API : map
- map 은 기본 데이터 유형의 스트림, 예를 들면 IntStream, LongStream, DoubleStream 등을 변환할 때 주로 사용됨
- 변환 후 반환되는 스트림도 기본 데이터 유형의 스트림
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
.mapToInt(x -> x * 2)
.forEach(System.out::println); // 2 4 6 8 10
● Java Stream API : mapToObj
- mapToObj 는 기본 데이터 유형의 스트림을 객체 스트림, 즉 Stream<T> 로 변환할 때 사용됨
- 변환 후의 반환 유형은 Stream<T> 이다
int[] numbers = {1, 2, 3, 4, 5};
Arrays.stream(numbers)
.mapToObj(x -> x * 2)
.forEach(System.out::println); // 2 4 6 8 10
● Java Stream API : map vs mapToObj
- 스트림에서는 일반적인 Stream 객체를 원시타입 Stream 으로 변환할 수 있는데, mapToObj 는 그 반대라고 생각하면 된다
-- 일반적인 Stream 객체 : ex. Stream<String>
-- 원시 Stream : ex. IntStream.range(1, 4)
Stream.of(1.0, 2.0)
.mapToInt(Double::intValue)
.mapToObj(String:valueOf)
.collect(Collectors.toList());
- 위의 코드에서 Stream<Double> 이라는 객체를 of() 메서드를 통해 생성하고 메서드 체인으로 int 타입으로 변경했음
- 여기서 mapToInt 는 일반적인 Stream 객체를 원시타입 IntSream 으로 변경한 것
- 이후 IntStream 을 mapToObj(String.valueOf) 메서드를 이용하여 원시타입 Stream 에서 Stream<String> 으로 변환함
● Collectors.joining()
- Stream 에서 작업한 결과를 1 개의 String 으로 이어붙이기를 원하는 경우에 Collectors.joining() 을 이용할 수 있음
- Collectors.joining() 은 총 3 개의 인자를 받을 수 있는데, 이를 이용하면 간단하게 String 조합 가능
-- delimiter : 각 요소 중간에 들어가 요소를 구분시켜 주는 구분자
-- prefix : 결과 맨 앞에 붙는 문자
-- suffix : 결과 맨 뒤에 붙는 문자
String listToString = productList.stream()
.map(Product::getName)
.collect(Collectors.joining());
// potatoesorangelemonbreadsugar
String listToString = productList.stream()
.map(Product::getName)
.collect(Collectors.joining(" "));
// potatoes orange lemon bread sugar
String listToString = productList.stream()
.map(Product::getName)
.collect(Collectors.joining(", ", "<", ">"));
// <potatoes, orange, lemon, bread, sugar>
import java.util.*;
class Solution {
public String solution(String str1, String str2) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < str1.length(); i++) {
sb.append(str1.charAt(i)).append(str2.charAt(i));
}
return sb.toString();
}
}
● StringBuffer 클래스 활용
문자 리스트를 문자열로 변환하기
class Solution {
public String solution(String[] arr) {
String answer = "";
for (int i = 0; i < arr.length; i++) {
answer += arr[i];
}
return answer;
}
}
● length : 배열의 크기 (int, double, float...)
● length() : 문자열의 길이
class Solution {
public String solution(String[] arr) {
return String.join("", arr);
}
}
● String.join(separator, value, startIndex, endIndex)
- 문자열 배열 내의 복수개의 요소들을 이어 붙일 수 있음
string[] value = {"apple", "orange", "grape", "pear"};
string separator = ", ";
string result = String.Join(separator, value, 1, 2);
Console.WriteLine(result); // orange, grape
string[] value = {"apple", "orange", "grape", "pear"};
string separator = ", ";
string result = String.Join(separator, value);
Console.WriteLine(result); // apple, orange, grape, pear
import java.util.Arrays;
import java.util.stream.Collectors;
class Solution {
public String solution(String[] arr) {
return Arrays.stream(arr).collect(Collectors.joining());
}
}
● Stream 생성
- 자료구조 형 (배열, 리스트, 맵 등) 마다 Stream 으로 바꿔서 사용 가능
String[] strs = {"a", "b", "c"};
Stream<String> stream = Arrays.stream(strs);
Stream<String> stream2 = Arrays.stream(arr, 1, 3); // b, c
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
Stream<String> parallelStream = list.parallelStream(); // 병렬 처리 스트림
Map<Integer, Integer> map = new HashMap<>();
Stream<Map.Entry<Integer, Integer>> stMap = map.entrySet().stream();
- 그 이외의 Stream 을 자료구조 형을 통해서 만드는 게 아니라 직접 만들 수도 있음
IntStream intStream = IntStream.range(1, 3); // 1, 2
LongStream longStream = LongStream.rangeClosed(1, 3); // 1, 2, 3
- 위처럼 int 형 Stream 도 만들 수 있는데, Collection 타입에 List<int> 가 불가능하고 List<Integer> 가 가능하듯이 int 로 구성된 Stream 도 Wrapper 형으로 고쳐서 사용해야 한다
Stream<Integer> boxedIntStream = IntStream.range(1, 5).boxed();
● Stream 사용 방법 : map
- 각 요소에 대해 특정 작업을 반복적으로 작업해 내어 결과물을 만들 때 사용
String[] strs = {"a", "b", "c"};
System.out.println(Arrays.stream(strs)
.map(s -> s.toUpperCase())
.collect(Collectors.toList()));
// [A, B, C]
● Stream 사용 방법 : filter
- map 처럼 반복작업은 하지만, if 조건이 붙은 것처럼 데이터를 거르는 역할을 한다
- map 을 통해서 사용하면 내부에 if 문도 적어야 하는데, 그럴 때 가독성을 위해 filter 를 이용하는 것이 좋음
String[] strs = {"apple", "banana", "carrot"};
System.out.println(Arrays.stream(strs)
.filter(t -> t.length() > 5)
.collect(Collectors.toList()));
// [banana, carrot]
- 장점 : Array 에서 특정 데이터만을 가져올 때 for 문에 비해 압도적으로 빠르다
// 650000000개만큼 stir 문자열 할당
String[] names = new String[650000000];
for (int i = 0; i < names.length; i++) {
names[i] = "stir";
}
// stir 데이터 전체 검사
long start = System.currentTimeMillis();
for(int i = 0; i < names.length; i++) {
if (names[i].equals("stir")) {
}
}
long end = System.currentTimeMillis();
System.out.println("실행 시간 : " + (end - start));
// stir 데이터 전체 필터링
start = System.currentTimeMillis();
Stream stream = Arrays.stream(names)
.filter(t -> t.startsWith("frodo"));
end = System.currentTimeMillis();
System.out.println("실행 시간 : " + (end - start));
//실행 시간 : 119
//실행 시간 : 0
● Stream 사용 방법 : sorted
- 데이터를 정렬
String[] strs = {"c", "b", "a"};
System.out.println(Arrays.stream(strs)
.sorted()
.collect(Collectors.toList()));
// [a, b, c]
int[] people = {70, 50, 80, 50};
System.out.println(Arrays.stream(people)
.sorted()
.boxed()
.collect(Collectors.toList()));
// [50, 50, 70, 80]
// sorted의 결과가 int형일땐 boxed를 해줘야 collect 사용 가능
● Stream 사용 방법 : collect
- 스트림의 아이템들을 List 또는 Set 자료형으로 변환
- 스트림의 아이템들을 joining (String 반환)
- 스트림의 아이템들의 평균값을 리턴
String[] strs = {"a", "b", "c", "c", "cc"};
System.out.println(Arrays.stream(strs)
.distinct()
.collect(Collectors.toList()));
// [a, b, c, cc]
System.out.println(Arrays.stream(strs)
.collect(Collectors.joining()));
// abcccc
List<Integer> list = Arrays.asList(1,2,3,4);
Double result = list.stream()
.collect(Collectors.averagingInt(v -> v * 2));
System.out.println("Average: " + result);
// Average: 5
● Stream 사용 방법 : reduce
Stream<String> stream1 = Stream.of("넷", "둘", "셋", "하나");
Stream<String> stream2 = Stream.of("넷", "둘", "셋", "하나");
Optional<String> result1 = stream1.reduce((s1, s2) -> s1 + "++" + s2);
result1.ifPresent(System.out::println);
String result2 = stream2.reduce("시작", (s1, s2) -> s1 + "++" + s2);
System.out.println(result2);
// 넷++둘++셋++하나
// 시작++넷++둘++셋++하나
- 스트림의 최종 연산은 모두 스트림의 각 요소를 소모하여 연산을 수행하게 됨
- reduce() 메소드는 첫 번째와 두 번째 요소를 가지고 연산을 수행한 뒤, 그 결과와 세 번째 요소를 가지고 또다시 연산을 수행함
- reduce 의 첫 인자에 위처럼 "시작" 이 담기면 해당 인자를 첫 번째로 두고 연산을 수행한다.
- 그럼 결과를 Optional 로 안 줘도 위처럼 String 으로 받을 수 있다고 함
// 문자열 중에 가장 긴 것만 반환하도록 한다.
String[] myList = {"안녕하세요", "안녕", "반가워"};
System.out.println(Arrays.stream(myList)
.reduce("", (s1,s2) -> {
if (s1.length() > s2.length()) return s1;
return s2;
}));
String[] myList = {"안녕하세요", "안녕", "반가워"};
String LongerEliment2 = myList.stream()
.reduce("test", (a, b) -> a.length() >= b.length() ? a : b);
System.out.println(LongerEliment2);
● Stream 의 최종 연산
- Stream 에서는 최종 연산이 존재하고 최종 연산을 거치지 않으면 결과물이 도출되지 않음
String[] strs = {"a", "b", "c"};
System.out.println(Arrays.stream(strs)
.map(s -> s.toUpperCase())
.collect(Collectors.toList()));
// [A, B, C]
- 여기서는 collect 가 최종 연산을 했기 때문에 결과물인 A, B, C 가 도출되는 것
- 최종 연산을 적어주지 않으면 Stream 은 map 안에 있는 내용 자체를 수행하지 않음
Map<String, Integer> names = new HashMap<>();
names.put("stir", 1);
// stir에 2 삽입을 했지만 최종 연산을 넣어주지 않아 실행하지 않음.
System.out.println(names.entrySet().stream()
.map(s -> names.put("stir", 2)));
System.out.println(names.get("stir")); // 실행 결과 1
// stir에 2 삽입을 했지만 최종 연산인 collect를 넣어줘서 map을 실행
System.out.println(names.entrySet().stream()
.map(s -> names.put("stir", 2))
.collect(Collectors.toList()));
System.out.println(names.get("stir")); // 실행 결과 2
- 즉 map 은 최종 연산을 해주지 않으면 결과를 반환하지 않음
- 최종 연산을 해서 return 이 필요할 경우에 사용하고, 단순히 결과가 필요하지 않고 반복적으로 작업만 하고 싶을 때는 forEach 만 사용하면 된다
names.entrySet().stream()
.forEach(s -> names.put("stir", 2)); // 2가 정상적으로 들어감
- forEach 자체가 최종 연산에 해당하므로 map 처럼 최종 연산이 필요하지 않다
● collect 기능의 심화
- HashMap 을 이용한 예시
String[][] clothes = {{"yellow_hat", "headgear"}, {"blue_sunglasses", "eyewear"}, {"green_turban", "headgear"}};
HashMap<String, HashSet> map = new HashMap();
for (int i = 0; i < clothes.length; i++) {
HashSet set = map.getOrDefault(clothes[i][1], new HashSet());
set.add(clothes[i][0]);
map.put(clothes[i][1], set);
}
System.out.println(map);
// eyewear=[blue_sunglasses], headgear=[yellow_hat, green_turban]}
- Stream 의 groupingBy 를 이용한 예시
String[][] clothes = {{"yellow_hat", "headgear"}, {"blue_sunglasses", "eyewear"}, {"green_turban", "headgear"}};
System.out.println(Arrays.stream(clothes)
.collect(groupingBy(p -> p[1])));
// {eyewear=[[Ljava.lang.String;@7cca494b], headgear=[[Ljava.lang.String;@7ba4f24f, [Ljava.lang.String;@3b9a45b3]}
System.out.println(Arrays.stream(clothes)
.collect(groupingBy(p -> p[1], mapping(p -> p[0], counting()))));
// {eyewear=1, headgear=2}
class Solution {
public String solution(String[] arr) {
StringBuilder sb = new StringBuilder();
for (String s : arr) {
sb.append(s);
}
return sb.toString();
}
}
● StringBuilder 활용
문자열 곱하기
class Solution {
public String solution(String my_string, int k) {
return my_string.repeat(k);
}
}
● String.repeat(int n)
- ex. "str".repeat(5) ▶ "strstrstrstrstr"
더 크게 합치기
class Solution {
public int solution(int a, int b) {
return Math.max(Integer.parseInt(a + "" + b), Integer.parseInt(b + "" + a));
}
}
● 자바 Math 클래스 메소드 정리
두 수의 연산값 비교하기
class Solution {
public int solution(int a, int b) {
int answer = 0;
int ab = Integer.parseInt("" + a + b);
int ab2 = 2 * a * b;
answer = ab2 > ab ? ab2 : ab;
return answer;
}
}
class Solution {
public int solution(int a, int b) {
return Math.max((int) Math.pow(10, (int) Math.log10(b) + 1) * a + b, 2 * a * b);
}
}
● 자바 Math 클래스 메소드 정리
홀짝에 따라 다른 값 반환하기
import java.util.stream.IntStream;
class Solution {
public int solution(int n) {
if (n % 2 == 0) {
return IntStream.rangeClosed(1, n)
.filter(i -> i % 2 == 0)
.map(i -> (int) Math.pow(i, 2))
.sum();
} else {
return IntStream.rangeClosed(1, n)
.filter(i -> i % 2 == 1)
.sum();
}
}
}
● IntStream 활용
조건 문자열
import java.util.Map;
import java.util.function.BiFunction;
class Solution {
public int solution(String ineq, String eq, int n, int m) {
Map<String, BiFunction<Integer, Integer, Boolean>> functions = Map.of(
">=", (a, b) -> a >= b,
"<=", (a, b) -> a <= b,
">!", (a, b) -> a > b,
"<!", (a, b) -> a < b
);
return functions.get(ineq + eq).apply(n, m) ? 1 : 0;
}
}
● Map.of
- 기존 맵 초기화
private Map<Integer, String> map = new HashMap<>() {
{
put(1, "sangwoo kang");
put(2, "james kang");
put(3, "stef you");
}
};
- Java 9 이상부터는 Map.of() 를 통해 조금 더 간단하게 맵 초기화 가능
-- 오버로딩 인자 개수 10개까지 제한 ▶ Map.ofEntries() 를 이용해 처리 가능
private Map<Integer, String> map = Map.of(
1, "sangwoo kang",
2, "james kang",
3, "stef you"
);
● BiFunction 인터페이스
- Java 에서 함수형 프로그래밍을 구현하기 위해 Java 버전 1.8 부터 도입된 함수형 인터페이스
- 두 개의 매개변수를 전달받아 특정 작업을 수행 후 새로운 값을 반환하는 경우 사용
- 제네릭 타입인 두 개의 인수가 존재하며, 제네릭 타입을 반환함
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);
default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t, U u) -> after.apply(apply(t, u));
}
}
- 세 개의 제네릭 타입을 사용함
-- T : 첫 번째 매개변수의 타입
-- U : 두 번째 매개변수의 타입
-- R : 반환 타입
● BiFunction 인터페이스의 apply 메서드
- 제네릭 타입인 두 개의 매개변수를 전달받아 특정 작업을 수행 후 값을 반환함
R apply(T t, U u);
- 예시
-- 먼저, 세 개의 BiFunction 타입의 객체를 생성하며 특정 로직을 수행하는 람다 표현식을 할당합니다.
-- biFunctionAdd 객체는 Integer 타입의 두 개의 매개변수를 전달받아 더한 결과를 문자열로 반환합니다.
-- biFunctionMinus 객체는 Integer 타입의 두 개의 매개변수를 전달받아 뺄셈 결과를 문자열로 반환합니다.
-- biFunctionMultiple 객체는 Integer 타입의 두 개의 매개변수를 전달받아 곱한 결과를 문자열로 반환합니다.
public static void main(String args[]) {
BiFunction<Integer, Integer, String> biFunctionAdd =
(num1, num2) -> Integer.toString(num1 + num2);
BiFunction<Integer, Integer, String> biFunctionMinus =
(num1, num2) -> Integer.toString(num1 - num2);
BiFunction<Integer, Integer, String> biFunctionMultiple =
(num1, num2) -> Integer.toString(num1 * num2);
System.out.println("100 + 50 = " + biFunctionAdd.apply(100, 50));
System.out.println("100 - 50 = " + biFunctionMinus.apply(100, 50));
System.out.println("100 * 50 = " + biFunctionMultiple.apply(100, 50));
}
//////// 실행 결과
// 100 + 50 = 150
// 100 - 50 = 50
// 100 * 50 = 5000
● BiFunction 인터페이스의 andThen 메서드
- apply() 메서드 실행 후 반환 결과에 대해 특정 작업이 필요한 경우 해당 로직을 andThen() 메서드에 전달함
- 매개변수로 전달되는 함수는 BiFunction 타입이 아니라 Function 타입이어야 함
- 예시 : apply() 메서드 반환 결과를 andThen() 메서드를 사용하여 문자열을 병합
public static void main(String args[]) {
BiFunction<Integer, Integer, String> biFunctionAdd =
(num1, num2) -> Integer.toString(num1 + num2);
biFunctionAdd = biFunctionAdd.andThen(result -> "biFunctionAdd Result: " + result);
BiFunction<Integer, Integer, String> biFunctionMinus =
(num1, num2) -> Integer.toString(num1 - num2);
biFunctionMinus = biFunctionMinus.andThen(result -> "biFunctionMinus Result: " + result);
BiFunction<Integer, Integer, String> biFunctionMultiple =
(num1, num2) -> Integer.toString(num1 * num2);
biFunctionMultiple = biFunctionMultiple.andThen(result -> "biFunctionMultiple Result: " + result);
System.out.println(biFunctionAdd.apply(100, 50));
System.out.println(biFunctionMinus.apply(100, 50));
System.out.println(biFunctionMultiple.apply(100, 50));
}
//////// 실행 결과
// biFunctionAdd Result: 150
// biFunctionMinus Result: 50
// biFunctionMultiple Result: 5000
코드 처리하기
class Solution {
public String solution(String code) {
StringBuilder answer = new StringBuilder();
int mode = 0;
for (int i = 0; i < code.length(); i++) {
char current = code.charAt(i);
if (current == '1') {
mode = mode == 0 ? 1 : 0;
continue;
}
if (i % 2 == mode) {
answer.append(current);
}
}
return answer.length() == 0 ? "EMPTY" : answer.toString();
}
}
● mode 를 나머지로 바로 활용
등차수열의 특정한 항만 더하기
import java.util.stream.IntStream;
class Solution {
public int solution(int a, int d, boolean[] included) {
return IntStream.range(0, included.length)
.map(idx -> included[idx] ? a + (idx * d) : 0)
.sum();
}
}
● IntStream 활용
주사위 게임 2
class Solution {
public int solution(int a, int b, int c) {
int answer = 1;
int count = 1;
if (a == b || a == c || b == c) {
count++;
}
if (a == b && b == c) {
count++;
}
for (int i = 1; i <= count; i++) {
answer *= (pow(a,i) + pow(b,i) + pow(c,i));
}
return answer;
}
private int pow(int a, int b) {
if (b == 0) return 1;
return a * pow(a, b-1);
}
}
● pow 클래스 오버라이딩
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
class Solution {
public int solution(int a, int b, int c) {
Set<Integer> numbers = Stream.of(a, b, c)
.collect(Collectors.toSet());
return (a + b + c) *
(numbers.size() < 3 ? a * a + b * b + c * c : 1) *
(numbers.size() < 2 ? a * a * a + b * b * b + c * c * c : 1);
}
}
● Stream 활용
원소들의 곱과 합
import java.util.Arrays;
class Solution {
public int solution(int[] numList) {
return Arrays.stream(numList)
.reduce((acc, i) -> acc * i)
.getAsInt()
< Math.pow(Arrays.stream(numList).sum(), 2) ? 1 : 0;
}
}
● Stream 활용
이어 붙인 수
import java.util.*;
import java.util.stream.Collectors;
class Solution {
public int solution(int[] numList) {
return Integer.parseInt(
Arrays.stream(numList)
.filter(value -> value % 2 != 0)
.mapToObj(String::valueOf)
.collect(Collectors.joining()))
+ Integer.parseInt(
Arrays.stream(numList)
.filter(value -> value % 2 == 0)
.mapToObj(String::valueOf)
.collect(Collectors.joining()));
}
}
● Stream 활용
마지막 두 원소
class Solution {
public int[] solution(int[] num_list) {
int[] answer = new int[num_list.length + 1];
for (int i = 0; i < num_list.length; i++) {
answer[i] = num_list[i];
}
answer[num_list.length] = num_list[num_list.length - 1] > num_list[num_list.length - 2] ? num_list[num_list.length - 1] - num_list[num_list.length - 2] : num_list[num_list.length - 1] * 2;
return answer;
}
}
import java.util.stream.IntStream;
class Solution {
public int[] solution(int[] num_list) {
return IntStream.iterate(0, i -> i + 1)
.limit(num_list.length + 1)
.map(i -> i == num_list.length ? (num_list[i - 1] > num_list[i - 2] ? num_list[i - 1] - num_list[i - 2] : 2 * num_list[i - 1]) : num_list[i])
.toArray();
}
}
● IntStream 활용
수 조작하기 1
class Solution {
public int solution(int n, String control) {
int answer = n;
for (char ch : control.toCharArray()) {
switch (ch) {
case 'w': answer += 1; break;
case 's': answer -= 1; break;
case 'd': answer += 10; break;
case 'a': answer -= 10; break;
default : break;
}
}
return answer;
}
}
● 향상된 for 문 활용
● String.toCharArray() 활용
class Solution {
public int solution(int n, String control) {
int answer = n;
Character[] con_arr = {'w', 'd', 's', 'a'};
int[] con_num = {1, 10, -1, -10};
for (int i = 0; i < control.length(); i++) {
for (int j = 0; j < con_arr.length; j++) {
if (control.charAt(i) == con_arr[j]) answer += con_num[j];
}
}
return answer;
}
}
class Solution {
public int solution(int n, String control) {
return control.chars()
.reduce(n,(acc, c) -> acc + (c == 'w' ? 1 : c == 's' ? -1 : c == 'd' ? 10 : -10));
}
}
● String.chars()
- 문자열을 구성하고 있는 문자들의 ASCII 코드값을 스트림 형태로 뽑아준다.
IntStream stream = "Hello,World".chars();
// (72, 101, 108, 108, 111, 44, 87, 111, 114, 108, 100)
수열과 구간 쿼리 3
import java.util.Arrays;
class Solution {
public int[] solution(int[] arr, int[][] queries) {
int[] answer = Arrays.copyOf(arr, arr.length);
for (int[] query : queries) {
int i = query[0];
int j = query[1];
int temp = answer[i];
answer[i] = answer[j];
answer[j] = temp;
}
return answer;
}
}
import java.util.Arrays;
● Arrays.copyOf()
- Arrays.copyOf(원본 배열, 복사할 길이)
- 지정한 배열을 인덱스 0 부터 원하는 길이만큼 복사
- 원본 배열이 입력한 길이보다 클 경우 입력한 길이 이후의 인덱스는 제거되어 copy 됨
- 원본 배열이 입력한 길이보다 작을 경우 원본 배열에서 존재하지 않는 인덱스 이후의 값은 배열의 타입 기본값으로 초기화되어 copy 됨
import java.util.Arrays;
int[] intArr = new int[] {1, 2, 3, 4, 5};
int[] intArrCopy = Arrays.copyOf(intArr, 3);
for (int i : intArrCopy) {
System.out.println(i);
}
// 출력
// 1
// 2
// 3
import java.util.Arrays;
String[] strArr = new String[] {"copy", "of", "method"};
String[] strArrCopy = Arrays.copyOf(strArr, 5);
for (String s : strArrCopy) {
System.out.println(s);
}
// 출력
// copy
// of
// method
// null
// null
● Arrays.copyOfRange()
- Arrays.copyOfRange(복사할 원본 배열, 복사를 시작할 인덱스, 복사를 끝낼 인덱스)
- 지정한 배열에서 특정 범위만큼의 요소들을 복사해 새로운 배열로 반환
- 복사할 배열의 길이가 복사를 끝낼 인덱스로 입력한 길이보다 작을 경우 원본 배열의 마지막 인덱스 이후의 값은 배열의 타입 기본값으로 초기화되어 copy 됨
- 주의. 복사를 시작할 인덱스로 복사할 원본 배열의 길이보다 큰 값을 주면 exception 이 발생해 처리되지 않음
import java.util.Arrays;
int[] intArr = new int[] {1, 2, 3, 4, 5};
int[] intArrCopy = Arrays.copyOfRange(intArr, 2, 4);
for (int i : intArrCopy) {
System.out.println(i);
}
// 출력
// 1
// 2
// 3
import java.util.Arrays;
String[] strArr = new String[] {"copy", "of", "range", "method"};
String[] strArrCopy = Arrays.copyOfRange(strArr, 3, 7);
for(String s : strArrCopy) {
System.out.println(s);
}
// 출력
// method // index = 3
// null
// null
// null // index = 6
● System.arraycopy()
- System.arraycopy(source_arr, sourcePos, dest_arr, desPos, len)
-- source_arr : 복사할 배열
-- sourcePos : (복사할 배열에서) 복사를 시작할 인덱스
-- des_arr : 붙여넣기 할 배열
-- desPos : 붙여넣기를 시작할 인덱스
-- len : (복사할 배열에서) 얼마나 복사해 붙여넣을지 길이를 지정
- sourcePos 에서 sourcePos + len - 1 만큼의 요소가 destPos 에서 destPos + len - 1 으로 복사됨
int[] intArr1 = new int[] {1, 2, 3, 4, 5};
int[] intArr2 = new int[] {99, 98, 97, 96, 95};
System.arraycopy(intArr1, 1, intArr2, 2, 3);
for(int i : intArr2) System.out.println(i);
// 출력
// 99
// 98
// 2
// 3
// 4
STEP 1. 배열 intArr1 의 요소를 배열 intArr2 로 복사한다
STEP 2. intArr1 의 인덱스 1 부터 인덱스 sourcePos + len - 1 = 3 만큼의 요소 {2, 3, 4} 를 복사한다
STEP 3. 복사한 요소를 배열 intArr2 의 인덱스 2 부터 붙여넣는다.
String[] strArr1 = new String[] {"example", "of"};
String[] strArr2 = new String[] {"system", "arraycopy", "method"};
String[] strArr3 = new String[strArr1.length + strArr2.length];
System.arraycopy(strArr1, 0, strArr3, 0, strArr1.length);
System.arraycopy(strArr2, 0, strArr3, strArr1.length, strArr2.length);
for (String s : strArr3) {
System.out.println(s);
}
// 출력
// example
// of
// system
// arraycopy
// method
STEP 1. 먼저 strArr1 과 strArr2 를 합치기 위해, 두 배열 길이의 합만큼을 길이로 갖는 배열 strArr3 를 선언한다
STEP 2. strArr3 에 먼저 strArr1 의 인덱스 0 부터 strArr1.length 만큼을 strArr3 의 인덱스 0 부터 복사해 붙여넣는다
STEP 3. 그다음 strArr2 의 인덱스 0 부터 strArr2.length 까지의 요소들을 strArr3 의 strArr1.length (=2) 에 해당하는 인덱스부터 붙여넣어 두 배열을 합침
import java.util.*;
import java.util.stream.Collectors;
class Solution {
public List<Integer> solution(int[] arr, int[][] queries) {
List<Integer> list = Arrays.stream(arr).boxed().collect(Collectors.toList());
for (int[] query : queries) {
Collections.swap(list, query[0], query[1]);
}
return list;
}
}
● Stream boxed() 메소드
- IntStream 같이 원시 타입에 대한 스트림 지원을 클래스 타입 (ex. IntStream ▶ Stream<Integer>) 으로 전환
- int[] ▶ Integer[]
public static void main(String[] args) {
//int[] -> IntStream -> Stream<Integer> -> Integer[]
int[] num = {3, 4, 5};
// 1. int[] -> IntStream
IntStream stream = Arrays.stream(num);
// 2. IntStream -> Stream<Integer>
Stream<Integer> boxed = stream.boxed();
// 3. Stream<Integer> -> Integer[]
Integer[] result = boxed.toArray(Integer[]::new);
System.out.println(Arrays.toString(result));
// one line
Integer[] oneLineResult = Arrays.stream(num)
.boxed()
.toArray(Integer[]::new);
}
- int[] ▶ List<Integer>
List<Integer> list1 = Arrays.stream(arr).boxed().collect(Collectors.toList());
List<Integer> list2 = IntStream.of(arr).boxed().collect(Collectors.toList());
- List<Integer> ▶ int[]
// 방법 1 - 직접 int[] 생성해서 넣기
int[] arr1 = new int[list.size()]
for (int i = 0; i < list.size(); i++) {
arr1[i] = list.get(i).intValue();
}
// 방법 2
int[] arr2 = list.stream()
.mapToInt(i -> i)
.toArray();
// 방법 3
int[] arr3 = list.stream()
.mapToInt(Integer::intValue)
.toArray();
- int[] ▶ Set<Integer>
// 방법 1. HashSet 의 인자에 List<Integer> 넣기
int[] ints = {1, 2, 3, 4};
Set<Integer> integerHashSet = new HashSet<>(Arrays.stream(ints).boxed().collect(Collectors.toList()));
// 방법 2. stream 으로 한 줄에 작성
Set<Integer> set = Arrays.stream(ints).boxed().collect(Collectors.toSet());
// 방법 3. int[] -> Integer[]
HashSet<Integer> hashset = IntStream.of(ints).boxed().collect(Collectors.toCollection(HashSet::new));
// 방법 4. add 로 for 문 돌려서 넣기
Set <Integer> integerHashSet = new HashSet <Integer>();
for (Integer t : ints) {
integerHashSet.add(t);
}
● Collections.swap()
import java.util.ArrayList;
import java.util.Collections;
public class Main {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<String>();
arrayList.add("A");
arrayList.add("B");
arrayList.add("C");
arrayList.add("D");
arrayList.add("E");
System.out.println(arrayList);
Collections.swap(arrayList, 0, 4);
System.out.println(arrayList);
}
}
/*
[A, B, C, D, E]
[E, B, C, D, A]
*/
수열과 구간 쿼리 2
import java.util.Arrays;
class Solution {
public int[] solution(int[] arr, int[][] queries) {
int[] answer = new int[queries.length];
Arrays.fill(answer, -1);
for (int idx = 0; idx < queries.length; idx++) {
int[] query = queries[idx];
int s = query[0], e = query[1], k = query[2];
for (int i = s; i <= e; i++) {
if (k < arr[i]) {
answer[idx] = answer[idx] == -1 ? arr[i] : Math.min(answer[idx], arr[i]);
}
}
}
return answer;
}
}
● Arrays.fill()
- Arrays 클래스에서 제공하는 메서드
- Java 11 부터 사용 가능
- 배열의 모든 값을 같은 값으로 초기화하는 메서드
public class ArrayFill {
public static void main(String[] args) {
// int 배열 선언
int[] arrayTest1 = new int[10];
int[] arrayTest2 = new int[10];
// 1. for문을 사용하여 배열을 채운다
for (int i = 0; i < arrayTest1.length; i++) {
arrayTest1[i] = 10;
}
// 2. Arrays.fill을 사용하여 배열을 채운다
Arrays.fill(arrayTest2, 10);
// 값을 입력할 StringBuilder 변수 선언
StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder();
sb1.append("ArrayTest1 = ");
sb2.append("ArrayTest2 = ");
// 반복문을 사용하여 배열의 값을 입력한다
for (int i = 0; i < 10; i++) {
sb1.append(arrayTest1[i] + " ");
sb2.append(arrayTest1[i] + " ");
}
// 결과 출력
System.out.println(sb1);
System.out.println(sb2);
}
}
import java.util.stream.IntStream;
class Solution {
public int[] solution(int[] arr, int[][] queries) {
return IntStream.range(0, queries.length)
.map(q -> IntStream.rangeClosed(queries[q][0], queries[q][1])
.map(i -> arr[i])
.filter(i -> i > queries[q][2])
.min()
.orElse(-1)
).toArray();
}
}
● IntStream.range(int startInclusive, int endExclusive)
- startInclusive 에서 endExclusive 사이의 integer 를 차례대로 스트림으로 방출
- for 의 경우
@Test
public void for_loop() {
for (int i = 1 ; i <= 10 ; i++) {
System.out.println(i);
}
}
- IntStream.range 의 경우
@Test
public void intStream_range() {
IntStream.range(1, 11).forEach(System.out::println);
}
● InStream.rangeClosed(int startInclusive, int endInclusive)
- range() 에서 마지막 숫자 포함
@Test
public void intStream_rangeClosed() {
IntStream.rangeClosed(1, 10).forEach(System.out::println);
}
import java.util.*;
class Solution {
public int[] solution(int[] arr, int[][] queries) {
int idx = 0;
int[] answer = new int[queries.length];
for (int[] query : queries) {
int s = query[0], e = query[1], k = query[2];
int min = Integer.MAX_VALUE;
for (int i = s; i <= e; i++) {
if (arr[i] > k) {
min = Math.min(arr[i], min);
}
}
answer[idx++] = min == Integer.MAX_VALUE ? -1 : min;
}
return answer;
}
}
import java.util.*;
class Solution {
public int[] solution(int[] arr, int[][] queries) {
return Arrays.stream(queries).mapToInt(q -> {
int min = Arrays.stream(arr, q[0], q[1] + 1).filter(n -> n > q[2]).min().orElse(-1);
return min == Integer.MAX_VALUE ? -1 : min;
}).toArray();
}
}
● Stream 활용
수열과 구간 쿼리 4
class Solution {
public int[] solution(int[] arr, int[][] queries) {
for (int i = 0; i < queries.length; i++) {
for (int j = queries[i][0]; j <= queries[i][1]; j++) {
if (j % queries[i][2] == 0) arr[j] += 1;
}
}
return arr;
}
}
배열 만들기 2
import java.util.ArrayList;
class Solution {
public int[] solution(int l, int r) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 1; i < 64; i++) {
int num = Integer.parseInt(Integer.toBinaryString(i)) * 5;
if (l <= num && num <= r) list.add(num);
}
return list.isEmpty() ? new int[] { -1 } : list.stream().mapToInt(i -> i).toArray();
}
}
import java.util.*;
import java.util.stream.*;
class Solution {
public int[] solution(int l, int r) {
List<Integer> filtered = IntStream.rangeClosed(l, r)
.filter(num -> String.valueOf(num).chars().allMatch(ch -> ch == '0' || ch == '5'))
.boxed()
.collect(Collectors.toList());
return filtered.isEmpty() ? new int[] {-1} : filtered.stream().mapToInt(Integer::intValue).toArray();
}
}
import java.util.stream.IntStream;
class Solution {
public int[] solution(int l, int r) {
int[] answer = IntStream.iterate(l, i -> i + 1)
.limit(r - l + 1)
.filter(i -> (i + "").replaceAll("[05]", "").isEmpty())
.toArray();
if (answer.length == 0) answer = new int[] {-1};
return answer;
}
}
● Intstram.iterate()
- for 의 경우
int sum = 0;
for (int i = 0; i < 10; i++) {
if (i % 2 == 1) {
sum += i;
}
}
System.out.println("합: " + sum); // 합: 25
- Java 8 의 iterate() 의 경우
int sum = Stream.iterate(0, i -> i + 1)
.filter(i -> i % 2 == 1)
.limit(5)
.mapToInt(Integer::intValue)
.sum();
System.out.println("합: " + sum); // 합: 25
- Java 9 의 iterate() 의 경우
int sum = Stream.iterate(0, i -> i < 10, i -> i + 1)
.filter(i -> i % 2 == 1)
.mapToInt(Integer::intValue)
.sum();
System.out.println("합: " + sum); // 합: 25
import java.util.*;
class Solution {
public int[] solution(int l, int r) {
// 이진법 활용
// l = 5, r = 555
// 5, 50, 55, 500, 505, 550, 555
// 1 10 11 100 101 110 111
// 1 2 3 4 5 6 7
// 지수는 자릿수
// 2^0 <= x < 2^3
int digit = String.valueOf(r).length();
int exponent = (int) Math.pow(2.0, digit);
List<Integer> list = new ArrayList<>();
for (int i = 0; i < exponent; i++) {
String binaryString = Integer.toBinaryString(i);
int target = Integer.parseInt(binaryString) * 5;
if (target >= l && target <= r) list.add(target);
}
if (list.isEmpty()) {
return new int[] {-1};
} else {
return list.stream().mapToInt(i -> i).toArray();
}
}
}
● Integer.toBinaryString(int number)
- 10 진수에서 2 진수로 변환
Integer.toBinaryString(8); // 1000
카운트 업
import java.util.stream.IntStream;
class Solution {
public int[] solution(int start, int end) {
return IntStream.rangeClosed(start, end).toArray();
}
}
● IntStream 활용
콜라츠 수열 만들기
import java.util.stream.IntStream;
class Solution {
public int[] solution(int n) {
return IntStream.concat(IntStream.iterate(n, i -> i > 1, i -> i % 2 == 0 ? i / 2 : i * 3 + 1),
IntStream.of(1)
)
.toArray();
}
}
● IntStream 활용
import java.util.LinkedList;
import java.util.Queue;
class Solution {
public int[] solution(int n) {
Queue<Integer> answer = new LinkedList<>();
while (n > 1) {
answer.add(n);
if (n % 2 == 0) n >>= 1;
else n = n * 3 + 1;
}
answer.add(1);
return answer.stream().mapToInt(i -> i).toArray();
}
}
● Queue 활용
import java.util.*;
import java.util.stream.Stream;
class Solution {
public int[] solution(int n) {
return Stream.iterate(n, i -> i >= 1, i -> i == 1 ? 0 : i % 2 == 0 ? i / 2 : 3 * i + 1)
.mapToInt(Integer::intValue)
.toArray();
}
}
● Stream 활용
import java.util.*;
class Solution {
public int[] solution(int n) {
ArrayList<Integer> al = new ArrayList<>();
al.add(n);
while (n != 1) {
if (n % 2 == 0) {
n /= 2;
} else {
n = (3 * n + 1);
}
al.add(n);
}
int[] answer = new int[al.size()];
for (int i = 0; i < answer.length; i++) {
answer[i] = al.get(i);
}
return answer;
}
}
class Solution {
public int[] solution(int n) {
String str = n + ",";
while (n != 1) {
n = n % 2 == 0 ? n / 2 : 3 * n + 1;
str += n + ",";
}
String[] arr = str.split(",");
int[] answer = new int[arr.length];
for (int i = 0; i < answer.length; i++) {
answer[i] = Integer.parseInt(arr[i]);
}
return answer;
}
}
배열 만들기 4
import java.util.*;
class Solution {
public Stack<Integer> solution(int[] arr) {
Stack<Integer> stack = new Stack<>();
int i = 0;
while (i < arr.length) {
if (stack.empty() || stack.peek() < arr[i]) {
stack.push(arr[i]);
i++;
} else if (stack.peek() >= arr[i]) {
stack.pop();
}
}
return stack;
}
}
● Stack 활용
간단한 논리 연산
class Solution {
public boolean solution(boolean x1, boolean x2, boolean x3, boolean x4) {
return (x1||x2)&&(x3||x4);
}
}
글자 이어 붙여 문자열 만들기
import java.util.*;
import java.util.stream.Collectors;
class Solution {
public String solution(String myString, int[] indexList) {
return Arrays.stream(indexList)
.mapToObj(operand -> String.valueOf(myString.charAt(operand)))
.collect(Collectors.joining());
}
}
● Stream 활용
참고문헌
https://dev-jwblog.tistory.com/108
https://data04190.tistory.com/59
https://velog.io/@zion9948/Stream%EC%97%90%EC%84%9C-MapToObj-%EB%9E%80