Open SDeung01 opened 1 year ago
두 정수 X, Y의 임의의 자리에서 공통으로 나타나는 정수 k(0 ≤ k ≤ 9)들을 이용하여 만들 수 있는 가장 큰 정수를 두 수의 짝꿍이라 합니다(단, 공통으로 나타나는 정수 중 서로 짝지을 수 있는 숫자만 사용합니다). X, Y의 짝꿍이 존재하지 않으면, 짝꿍은 -1입니다. X, Y의 짝꿍이 0으로만 구성되어 있다면, 짝꿍은 0입니다.
예를 들어, X = 3403이고 Y = 13203이라면, X와 Y의 짝꿍은 X와 Y에서 공통으로 나타나는 3, 0, 3으로 만들 수 있는 가장 큰 정수인 330입니다. 다른 예시로 X = 5525이고 Y = 1255이면 X와 Y의 짝꿍은 X와 Y에서 공통으로 나타나는 2, 5, 5로 만들 수 있는 가장 큰 정수인 552입니다(X에는 5가 3개, Y에는 5가 2개 나타나므로 남는 5 한 개는 짝 지을 수 없습니다.) 두 정수 X, Y가 주어졌을 때, X, Y의 짝꿍을 return하는 solution 함수를 완성해주세요.
제한사항
- 3 ≤ X, Y의 길이(자릿수) ≤ 3,000,000입니다.
- X, Y는 0으로 시작하지 않습니다.
- X, Y의 짝꿍은 상당히 큰 정수일 수 있으므로, 문자열로 반환합니다.
import java.util.HashMap;
import java.util.Map;
import java.lang.Math;
class Solution {
public String solution(String X, String Y) {
String answer = "";
Map<Integer, Integer> mapX = freqMap(X);
Map<Integer, Integer> mapY = freqMap(Y);
StringBuilder sb = new StringBuilder("");
// 큰 수 부터 작은 수로 반복해야 가장 큰 값을 구할 수 있다.
// "00~0"의 경우 "0"으로 출력되어야 하므로 반복횟수를 1회
// 그 외는 같은 숫자의 중복도 중 낮은 값으로 반복한다.
// (예를 들어 2가 각각 2개 3개 있다면 2번만 사용할 수 있다.)
for(int i = 9; i >= 0; i--){
if(mapX.containsKey(i) && mapY.containsKey(i)){
int repeat = (i == 0) && (sb.toString().equals("")) ? 1 : Math.min(mapX.get(i),mapY.get(i));
sb.append(makeNum(i,repeat));
}
} answer = sb.toString();
// 만약 마지막까지 동일한 숫자가 없다면 "-1" 을 반환한다.
return answer.equals("") ? "-1" : answer;
}
// 0~9 사이에 존재하는 정수 k의 중복도를 value로 가지는 Map을 반환한다.
private Map<Integer, Integer> freqMap(String strNum){
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < strNum.length(); i++){
int key = strNum.charAt(i) - '0';
map.put(key, map.getOrDefault(key, 0) + 1);
} return map;
}
// 숫자를 중복도만큼 반복한 문자열을 반환한다.
private String makeNum(int i, int repeatCnt){
String num = Integer.toString(i);
return num.repeat(repeatCnt);
}
}
import java.lang.Math;
class Solution { public String solution(String X, String Y) { int[] arrX = makeArr(X); int[] arrY = makeArr(Y);
StringBuilder sb = new StringBuilder("");
for(int i = 9; i >= 0; i--){
if(arrX[i] > 0 && arrY[i] > 0){
sb.append(makeNum(i,arrX[i],arrY[i]));
}
}
String answer = sb.toString();
return answer.equals("") ? "-1" :
answer.charAt(0) == '0' ? "0" : answer;
}
private int[] makeArr(String strNum){
int[] arr = new int[10];
for(char ch : strNum.toCharArray()){
int num = ch - '0';
arr[num] += 1;
}
return arr;
}
private String makeNum(int i, int X, int Y){
String num = Integer.toString(i);
return num.repeat(Math.min(X, Y));
}
}
![image](https://github.com/enoch012/JavaBasicStudy/assets/145359737/2f6a8d6d-9d05-4327-8d5e-38dc98935760)
- numbers 배열의 크기는 1 이상 1,000 이하입니다.
- numbers 배열 원소의 값은 0 이상 9 이하인 정수입니다.
- hand는 "left" 또는 "right" 입니다.
- "left"는 왼손잡이, "right"는 오른손잡이를 의미합니다.
- 왼손 엄지손가락을 사용한 경우는 L, 오른손 엄지손가락을 사용한 경우는 R을 순서대로 이어붙여 문자열 형태로 return 해주세요.
import java.util.*;
class Solution {
public String solution(int[] numbers, String hand) {
//indexOf를 사용하기 위해 키패드의 키들을 List 형태로 저장
// *과 #은 사용하지 않으므로 각각 최대값과 최소값으로 임의지정하여 넣음
int star = Integer.MAX_VALUE, sharp = Integer.MIN_VALUE;
List<Integer> keypad = Arrays.asList(1,2,3,4,5,6,7,8,9,star,0,sharp);
// 이전 손가락의 위치(시작지점 *,#)
int[] prev_L = {1,4}, prev_R = {3,4};
StringBuilder sb = new StringBuilder();
// 규칙에 맞춰 "L" 또는 "R"을 문자열에 더한다
for(int number : numbers){
int [] now = location(keypad,number);
if(number % 3 == 1){
sb.append("L");
prev_L = now;
} else if (number % 3 == 0 && number != 0){
sb.append("R");
prev_R = now;
} else {
int distance_L = distance(now, prev_L);
int distance_R = distance(now, prev_R);
if(distance_L < distance_R) {
sb.append("L");
prev_L = now;
} else if (distance_L > distance_R) {
sb.append("R");
prev_R = now;
} else {
if(hand.equals("left")) {
sb.append("L");
prev_L = now;
} else {
sb.append("R");
prev_R = now;
}
}
}
}
return sb.toString();
}
// 1차원인 keypad의 List를 3으로 나누어 몫과 나머지로 x,y 좌표를 구하여 반환
private int[] location(List<Integer> keypad, int number){
int xPoint = (keypad.indexOf(number) % 3) + 1;
int yPoint = (keypad.indexOf(number) / 3) + 1;
int[] loc = {xPoint, yPoint};
return loc;
}
// 손가락이 위치한 키에서 눌러야할 키 까지 거리를 측정하여 반환
private int distance(int[] now, int[] prev){
return Math.abs(prev[0] - now[0]) + Math.abs(prev[1] - now[1]);
}
}
for(int number : numbers){
int [] now = location(keypad,number);
if(number % 3 == 1){
sb.append("L");
} else if (number % 3 == 0 && number != 0){
sb.append("R");
} else {
int distance_L = distance(now, prev_L);
int distance_R = distance(now, prev_R);
if(distance_L < distance_R) {
sb.append("L");
} else if (distance_L > distance_R) {
sb.append("R");
} else {
if(hand.equals("left")) {
sb.append("L");
} else {
sb.append("R");
}
}
} if(sb.charAt(sb.length()-1) == 'L') {
prev_L = now;
} else {
prev_R = now;
}
}
return sb.toString();
}
문제 1: 핸드폰 번호 가리기
문제
입출력 예
phone_number | return -- | -- "01033334444" | "*******4444" "027778888" | "*****8888"문제 풀이
가장 먼저 푼 일반적인 풀이법.
주어진 문자열의 길이를 측정하고 그것을 기준으로 문자열을 자를 위치의 인덱스를 구한다.
잘라낸 문자열만큼 "*"을 repeat하여 합쳐준다.
실행 속도의 아쉬움이 있을 것을 예상하고 StringBuilder를 사용하여 리팩토링해보았다.
위가 String '+' 연산, 아래가 StringBuilder를 사용한 코드의 실행속도다.
예상한대로 상당히 큰 차이가 난다. 문자열 조작이 반복되는 문제라면 습관처럼 StringBuilder를 사용할 수 있도록 하는 것이 좋겠다.
회고
String.valueOf()
로 출력한다.