배열의 길이를 2의 거듭제곱으로 만들기
이 문제의 관건은 거듭제곱이 되겠네요. 현재 배열의 길이가 거듭제곱인지 아닌지는 어떻게 알 수 있을까요? 당연히 이미 만들어진 함수가 존재합니다. 하지만 그전에 비트 연산자에 대해서 알아보겠습니다.
public static boolean isPowerOfTwo(int n){
return n > 0 && (n & (n - 1)) == 0;
}
위에 함수는 n의 값이 거듭제곱인지 아닌지를 알 수 있습니다.
if n = 6,
6 → 0110 (2진수)
n - 1 = 5 → 0101 (2진수)
6 & 5 = 0100 -> 4 != 0
so, return false;
다음과 같은 함수를 통해 거듭제곱의 유무를 확인할 수 있습니다.
하지만, highestOneBit() 라는 함수를 통해 문제를 해결해보겠습니다
highestOneBit()는 인수로 들어오는 값의 가장 높은 비트를 반환합니다
Integer.highestOfBit(6) -> 4
Integer.highestOfBit(58) -> 32
0110 -> 0100
111010 -> 100000
그럼 이제 아래와 같이 문제를 해결할 수 있습니다.
import java.util.Arrays;
class Solution {
public int[] solution(int[] arr) {
int length = arr.length;
int nextPowerOfTwo = Integer.highestOneBit(length) * 2;
if(length == Integer.highestOneBit(length)) return arr;
int[] answer = Arrays.copyOf(arr, nextPowerOfTwo); // 나머지는 모두 0으로 채움
return answer;
}
}
문자열 묶기
이 문제는 두가지 풀이가 있을 것 같습니다. HashMap을 통해 key, value로 묶어서 배열을 순회하며 푸는 방법과 Stream API를 사용하는 방법이 있습니다
일단 HashMap으로 접근하는 방법은 Key = 문자열의 길이, Value = 빈도 수로 두고 배열을 순회하면서 저장합니다
import java.util.HashMap;
class Solution {
public int solution(String[] strArr) {
HashMap<Integer, Integer> map = new HashMap<>();
for (String str : strArr) {
int length = str.length();
map.put(length, map.getOrDefault(length, 0) + 1);
}
int maxValue = 0;
for(int value: map.values()){
if(maxValue < value) maxValue = value;
}
return maxValue;
}
}
Stream API 만으로도 가독성있게 클린한 코드를 작성할 수 있습니다
import java.util.Arrays;
class Solution {
public int solution(String[] strArr) {
return Arrays.stream(strArr)
.collect(Collectors.groupingBy(String::length, Collectors.counting()))
.values()
.stream()
.max(Long::compare)
.orElse(0L)
.intValue()
}
}
실행 과정
Arrays.stream(strArr)
→ Stream of ["a", "bc", "d", "efg", "hi"].
.collect(Collectors.groupingBy(String::length, Collectors.counting()))
→ {1=2, 2=2, 3=1}.
.values()
→ [2, 2, 1].
.stream()
→ Stream of [2, 2, 1].
.max(Long::compare)
→ 2L.
.orElse(0L)
→ 2L.
.intValue()
→ 2.
위에서 :: 연산자는 메서드 레퍼런스(Method Reference)라고 불리는 Java의 기능입니다. 람다 표현식을 더 간결하게 작성하는 방식입니다.
str -> str.length() == String::length
배열의 길이에 따라 다른 연산하기
이 문제도 stream으로 해결할 수 있습니다. IntStream.range()를 활용하여 문제를 해결해보겠습니다
import java.util.Arrays;
import java.util.stream.IntStream;
class Solution {
public int[] solution(int[] arr, int n) {
return IntStream.range(0, arr.length)
.map(i -> {
if ((arr.length % 2 == 0 && i % 2 != 0) || (arr.length % 2 != 0 && i % 2 == 0)) {
return arr[i] + n;
} else {
return arr[i];
}
})
.toArray();
}
}
배열의 길이만큼 반복을 진행하면서, 배열의 길이가 짝수고, 인덱스가 홀수면 해당 배열에 n을 더하는 익명 함수를 통해서 처리했습니다