Programmers #33

이강용·2023년 8월 19일
0

Programmers

목록 보기
32/58

신고 결과 받기

📑 문1) 신입사원 무지는 게시판 불량 이용자를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발하려 합니다. 무지가 개발하려는 시스템은 다음과 같습니다.

  • 각 유저는 한 번에 한 명의 유저를 신고할 수 있습니다.
    • 신고 횟수에 제한은 없습니다. 서로 다른 유저를 계속해서 신고할 수 있습니다.
    • 한 유저를 여러 번 신고할 수도 있지만, 동일한 유저에 대한 신고 횟수는 1회로 처리됩니다.
  • k번 이상 신고된 유저는 게시판 이용이 정지되며, 해당 유저를 신고한 모든 유저에게 정지 사실을 메일로 발송합니다.
    • 유저가 신고한 모든 내용을 취합하여 마지막에 한꺼번에 게시판 이용 정지를 시키면서 정지 메일을 발송합니다.

다음은 전체 유저 목록이 ["muzi", "frodo", "apeach", "neo"]이고, k = 2(즉, 2번 이상 신고당하면 이용 정지)인 경우의 예시입니다.

유저 ID유저가 신고한 ID설명
"muzi""frodo""muzi"가"frodo"를 신고했습니다.
"apeach""frodo""apeach"가"frodo"를 신고했습니다.
"frodo""neo""frodo"가"neo"를 신고했습니다.
"muzi""neo""muzi"가"neo"를 신고했습니다.
"apeach""muzi""apeach"가"muzi"를 신고했습니다.

각 유저별로 신고당한 횟수는 다음과 같습니다.

유저 ID신고당한 횟수
"muzi"1
"frodo"2
"apeach"0
"neo"2

위 예시에서는 2번 이상 신고당한 "frodo"와 "neo"의 게시판 이용이 정지됩니다. 이때, 각 유저별로 신고한 아이디와 정지된 아이디를 정리하면 다음과 같습니다.

유저 ID유저가 신고한 ID정지된 ID
"muzi"["frodo","neo"]["frodo","neo"]
"frodo"["neo"]["neo"]
"apeach"["muzi","frodo"]["frodo"]
"neo"없음없음

따라서 "muzi"는 처리 결과 메일을 2회, "frodo"와 "apeach"는 각각 처리 결과 메일을 1회 받게 됩니다.

이용자의 ID가 담긴 문자열 배열 id_list, 각 이용자가 신고한 이용자의 ID 정보가 담긴 문자열 배열 report, 정지 기준이 되는 신고 횟수 k가 매개변수로 주어질 때, 각 유저별로 처리 결과 메일을 받은 횟수를 배열에 담아 return 하도록 solution 함수를 완성해주세요.


제한사항

  • 2 ≤ id_list의 길이 ≤ 1,000
    • 1 ≤ id_list의 원소 길이 ≤ 10
    • id_list의 원소는 이용자의 id를 나타내는 문자열이며 알파벳 소문자로만 이루어져 있습니다.
    • id_list에는 같은 아이디가 중복해서 들어있지 않습니다.
  • 1 ≤ report의 길이 ≤ 200,000
    • 3 ≤ report의 원소 길이 ≤ 21
    • report의 원소는 "이용자id 신고한id"형태의 문자열입니다.
    • 예를 들어 "muzi frodo"의 경우 "muzi"가 "frodo"를 신고했다는 의미입니다.
    • id는 알파벳 소문자로만 이루어져 있습니다.
    • 이용자id와 신고한id는 공백(스페이스)하나로 구분되어 있습니다.
    • 자기 자신을 신고하는 경우는 없습니다.
  • 1 ≤ k ≤ 200, k는 자연수입니다.
  • return 하는 배열은 id_list에 담긴 id 순서대로 각 유저가 받은 결과 메일 수를 담으면 됩니다.

입출력 예

id_listreportkresult
["muzi", "frodo", "apeach", "neo"]["muzi frodo","apeach frodo","frodo neo","muzi neo","apeach muzi"]2[2,1,1,0]
["con", "ryan"]["ryan con", "ryan con", "ryan con", "ryan con"]3[0,0]

나의 풀이

package programmers;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;

public class GetReportResults {
	
	public static int[] solution(String[] id_list, String[] reports, int k) {
        
        LinkedHashMap<String, List<String>> map = new LinkedHashMap<>();
        LinkedHashMap<String, Integer> suspendID = new LinkedHashMap<>();
        for(String list : id_list) {
        	map.put(list, new ArrayList<>());
        	suspendID.put(list, 0);
        }
        
        for(String report : reports) {
        	String reporter = report.split(" ")[0];
        	String reported = report.split(" ")[1];
        	
        	if (map.containsKey(reporter) && !map.get(reporter).contains(reported)) {
                map.get(reporter).add(reported); 
            }
        	
        }
        
        for(List<String> reportedList : map.values()) {
        	for(String reported : reportedList) {
        		suspendID.put(reported, suspendID.get(reported) + 1);
        	}
        }
        
        
        int[] answer = new int[id_list.length];
        for(int i = 0; i < id_list.length; i++) {
        	String user = id_list[i];
        	List<String> reportedList = map.get(user);
        	for(String reported : reportedList) {
        		if(suspendID.get(reported) >= k) {
        			answer[i]++;
        		}
        	}
        	
        }
                
        
        return answer;
    }
	
	
	public static void main(String[] args) {
		solution(new String[] {"muzi", "frodo", "apeach", "neo"}, new String[] {"muzi frodo","apeach frodo","frodo neo","muzi neo","apeach muzi"}, 2);
	}

}

나의 생각

매개변수로 주어지는 id_list = {"muzi", "frodo", "apeach", "neo"} 라고 할 때, muzi가 신고한 사람, frodo가 신고한 사람, apeach가 신고한 사람, neo가 신고한 사람이 누구인지를 먼저 판단하는 로직이 필요하다라고 생각하였다. 그리고 신고한 사람이 0명 또는 한명 또는 여러명으로 이루어질 수 있기때문에, 요소를 쉽게 추가하고, 제거하기 쉬운 map(<리스트>)를 사용하였다. 그리고 신고당한 사람은 몇번 신고 당했는지를 판단할 수 있는 map을 추가하였다.

LinkedHashMap<String, List<String>> map = new LinkedHashMap<>();
LinkedHashMap<String, Integer> suspendID = new LinkedHashMap<>();

for(String list : id_list) {
	map.put(list, new ArrayList<>());
    suspendID.put(list, 0);
 }

초기의 형태

매개변수 reports에는 누가 누구를 신고 했는지 내용이 String 배열로 나타나있다.
String[] {"muzi frodo","apeach frodo","frodo neo","muzi neo","apeach muzi"}

muzi → frodo, neo
frodo → neo
apeach → frodo, muzi
neo → 없음

for(String report : reports) {
	String reporter = report.split(" ")[0];
    String reported = report.split(" ")[1];
        	
    if (map.containsKey(reporter) && !map.get(reporter).contains(reported)) {
    	map.get(reporter).add(reported); 
    }
        	
}

해당 로직은 향상된 for문으로 reports를 순회하며, 지역변수 reporter,reported를 띄어쓰기를 기준으로 [0] 은 reporter, [1]은 reported가 된다.

map에 신고자(reporter)가 key값으로 존재하고, 해당 신고자가 신고당한 자를 여러번 신고 했을 때는 1회만 인정되도록 하여, map에 신고자에 대한 신고당한 자를 map에 추가한다.

for(List<String> reportedList : map.values()) {
	for(String reported : reportedList) {
    	suspendID.put(reported, suspendID.get(reported) + 1);
    }
}

해당 로직은 신고당한 자의 신고횟수를 카운팅 하는 로직으로 suspendID에 포함된 key값에 대한 value값을 1씩 증가시킨다.

int[] answer = new int[id_list.length];
for(int i = 0; i < id_list.length; i++) {
	String user = id_list[i];
    List<String> reportedList = map.get(user);
    for(String reported : reportedList) {
    	if(suspendID.get(reported) >= k) {
        	answer[i]++;
        }
    }
        	
}

해당 로직이 이 문제의 핵심이며, user에 대한 reportedList를 순회하여 suspendID.get(reported)를 통해 횟수를 체크하여 매개변수 k 이상 신고당하면 계정 정지가 되도록 하는 로직이다. 예를들어, user muzi는 frodo와 neo를 신고했는데, frodo, neo는 신고 횟수가 2번 이상이기 때문에, answer[0]값이 2로 증가한다. frodo는 neo를 신고했는데, neo 역시 2번 신고 당했기때문에, answer[1]값이 1 증가한다. 최종적으로 answer 배열에 든 값은 다음과 같다.


🎉 Lv.1 -> Lv.2

최댓값과 최솟값

📑 문2) 문자열 s에는 공백으로 구분된 숫자들이 저장되어 있습니다. str에 나타나는 숫자 중 최소값과 최대값을 찾아 이를 "(최소값) (최대값)"형태의 문자열을 반환하는 함수, solution을 완성하세요.
예를들어 s가 "1 2 3 4"라면 "1 4"를 리턴하고, "-1 -2 -3 -4"라면 "-4 -1"을 리턴하면 됩니다.


제한 조건

  • s에는 둘 이상의 정수가 공백으로 구분되어 있습니다.

입출력 예

sreturn
"1 2 3 4""1 4"
"-1 -2 -3 -4""-4 -1"
"-1 -1""-1 -1"

나의 풀이

테스트 케이스는 통과하지만 런타임 에러가 발생한 로직

package programmers;

public class MaxValueMinValue {
	
	public static String solution(String s) {
        int minValue = Integer.MAX_VALUE;
        int maxValue = Integer.MIN_VALUE;
        
        int length = 0;
        for(int i = 0; i < s.length(); i++) {
        	if(Character.isDigit(s.charAt(i))) {
        		length++;
        	}
        	
        }
    
        
        for(int i = 0; i < length; i++) {
        	if(minValue > Integer.parseInt(s.split(" ")[i])) {
        		minValue = Integer.parseInt(s.split(" ")[i]);
        	}
        	
        	if(maxValue < Integer.parseInt(s.split(" ")[i])) {
        		maxValue = Integer.parseInt(s.split(" ")[i]);
        	}
        }
        
      
        System.out.println(minValue + " " + maxValue);
        
        return minValue + " " + maxValue;
    }
	
	public static void main(String[] args) {
		solution("1 2 3 4");
	}
	
	

}

나의 생각

매개변수 s 의 형태를 보면 1 2 3 4 숫자 사이에 공백이 존재함을 알 수 있다.

for(int i = 0; i < s.length(); i++) {
	if(Character.isDigit(s.charAt(i))) {
    	length++;
    }
        	
}

매개변수 s에서 각 글자를 char형으로 변환뒤, isDigit 메서드를 활용해서 숫자가 몇개인지 체크를 한다. 그리고 int형 length에 카운트를 저장

for(int i = 0; i < length; i++) {
	if(minValue > Integer.parseInt(s.split(" ")[i])) {
    	minValue = Integer.parseInt(s.split(" ")[i]);
    }
        	
    if(maxValue < Integer.parseInt(s.split(" ")[i])) {
    	maxValue = Integer.parseInt(s.split(" ")[i]);
    }
}

최소, 최대값을 찾는 로직으로, length길이 만큼 순회 한다. Integer.parseInt 메서드로 String타입을 int형으로 변환하여 minValue , MaxValue에 저장


런타임 문제를 해결한 로직

package programmers;

public class MaxValueMinValue {
	
	public static String solution(String s) {
        int minValue = Integer.MAX_VALUE;
        int maxValue = Integer.MIN_VALUE;
        
        String[] arrays = s.split(" ");
        
        for(String array : arrays) {
        	int value = Integer.parseInt(array);
        	
        	if(minValue > value) minValue = value;
        	if(maxValue < value) maxValue = value;
        	
        }
        
        return minValue + " " + maxValue;
    }
	
	public static void main(String[] args) {
		solution("-1 2 3 4");
	}
	
	

}

나의 생각

런타임 에러가 발생했던 로직에서 매개변수 s에서 숫자가 몇개인지 체크를 했다면, 이번 로직에서는 String타입의 배열을 하나 생성하여 s.split(" ")값을 넣어준다.

s.split(" ")[i] 에서 split 연산은 상대적으로 느린 연산이기 때문에 이러한 호출 방식을 최대한 피하는 것을 추천


JadenCase 문자열 만들기

📑 문3) adenCase란 모든 단어의 첫 문자가 대문자이고, 그 외의 알파벳은 소문자인 문자열입니다. 단, 첫 문자가 알파벳이 아닐 때에는 이어지는 알파벳은 소문자로 쓰면 됩니다. (첫 번째 입출력 예 참고)
문자열 s가 주어졌을 때, s를 JadenCase로 바꾼 문자열을 리턴하는 함수, solution을 완성해주세요.


제한 조건

-s 는 길이 1 이상 200 이하인 문자열입니다.

  • s는 알파벳과 숫자, 공백문자(" ")로 이루어져 있습니다.
    • 숫자는 단어의 첫 문자로만 나옵니다.
    • 숫자로만 이루어진 단어는 없습니다.
    • 공백문자가 연속해서 나올 수 있습니다.

입출력 예

sreturn
3people unFollowed me3people Unfollowed Me
for the last weekFor The Last Week

나의 풀이

package programmers;

public class JadenCase {
	
	 public static String solution(String s) {
	       	StringBuilder answer = new StringBuilder();
	       	String[] words = s.split(" ", -1);
	       	
	       	for(int i = 0; i < words.length; i++) {
	       		if(words[i].length() > 0) {
	       			char firstChar = words[i].charAt(0);
	       			answer.append(Character.toUpperCase(firstChar));
	       			answer.append(words[i].substring(1).toLowerCase());
	       		}
	       		
	       		if( i < words.length - 1) {
	       			answer.append(" ");
	       		}
	       	}
	       
	        
	        return answer.toString();
     }
	 
	 public static void main(String[] args) {
		solution("3people unFollowed me ");
	}
	 

}

다른 풀이 법

package programmers;

public class JadenCase {
	
	 public static String solution(String s) {
	       
		 
		 String result = "";
		 
		 String[] wordsArray = s.toLowerCase().split("");
		 boolean isNewWord = true;
		 
		 for(String charater : wordsArray) {
			 
			result += isNewWord ? charater.toUpperCase() : charater;
		    isNewWord = charater.equals(" ");
		 }
		 
	
		 
		 System.out.println(result);
		 return result;
     }
	 
	 public static void main(String[] args) {
		solution("3people unFollowed me ");
	}
	 

}

최솟값 만들기

📑 문3) 길이가 같은 배열 A, B 두개가 있습니다. 각 배열은 자연수로 이루어져 있습니다.
배열 A, B에서 각각 한 개의 숫자를 뽑아 두 수를 곱합니다. 이러한 과정을 배열의 길이만큼 반복하며, 두 수를 곱한 값을 누적하여 더합니다. 이때 최종적으로 누적된 값이 최소가 되도록 만드는 것이 목표입니다. (단, 각 배열에서 k번째 숫자를 뽑았다면 다음에 k번째 숫자는 다시 뽑을 수 없습니다.)

예를 들어 A = [1, 4, 2] , B = [5, 4, 4] 라면

  • A에서 첫번째 숫자인 1, B에서 첫번째 숫자인 5를 뽑아 곱하여 더합니다. (누적된 값 : 0 + 5(1x5) = 5)
  • A에서 두번째 숫자인 4, B에서 세번째 숫자인 4를 뽑아 곱하여 더합니다. (누적된 값 : 5 + 16(4x4) = 21)
  • A에서 세번째 숫자인 2, B에서 두번째 숫자인 4를 뽑아 곱하여 더합니다. (누적된 값 : 21 + 8(2x4) = 29)

즉, 이 경우가 최소가 되므로 29를 return 합니다.

배열 A, B가 주어질 때 최종적으로 누적된 최솟값을 return 하는 solution 함수를 완성해 주세요.


제한사항

  • 배열 A, B의 크기 : 1,000 이하의 자연수
  • 배열 A, B의 원소의 크기 : 1,000 이하의 자연수

입출력 예

ABanswer
[1,4,2][5,4,4]29
[1,2][3,4]10

입출력 예 설명

입출력 예 #2

  • A에서 첫번째 숫자인 1, B에서 두번째 숫자인 4를 뽑아 곱하여 더합니다. (누적된 값 : 4) 다음, A에서 두번째 숫자인 2, B에서 첫번째 숫자인 3을 뽑아 곱하여 더합니다. (누적된 값 : 4 + 6 = 10)
    이 경우가 최소이므로 10을 return 합니다.

나의 풀이

처음 시도한 방법

package programmers;

import java.util.ArrayList;
import java.util.Collections;

public class MakeMinValue {
	
    public static int solution(int []A, int []B) {
        int answer = 0;
        ArrayList<Integer> AList = new ArrayList<>();
        ArrayList<Integer> BList = new ArrayList<>();
        
        for(int a : A) {
        	AList.add(a);
        }
        
        for(int b : B) {
        	BList.add(b);
        }
        
       while(AList.size() > 0) {
    	   Integer max = Collections.max(AList);
    	   Integer min = Collections.min(BList);
    	   System.out.println("max: " + max +", "+"min: "+min);
    	   
    	   answer += max * min;
    	   AList.remove(max);
    	   BList.remove(min);
    	   
       }
       
        return answer;
    }
    
    public static void main(String[] args) {
		solution(new int[] {1,2}, new int[] {3,4});
	}

}

ArrayListint[] A, B를 추가하고 max, min 값을 뽑은 뒤 리스트에서 다시 그 값을 제거하는 방식을 사용

두번째 방법

package programmers;

import java.util.Arrays;

public class MakeMinValue {
	
    public static int solution(int []A, int []B) {
        int answer = 0;
        Arrays.sort(A);
        Arrays.sort(B);
        
        int length = A.length;
        for(int i = 0; i < length; i++) {
        	answer += A[i] * B[length - 1 - i];
        }
        
       
        return answer;
    }
    
    public static void main(String[] args) {
		solution(new int[] {1,4,2}, new int[] {5,4,4});
	}

}


나의 생각

결국, 이 문제의 핵심은 매개변수 int[] A,B 를 가지고, A에서는 max값을, B에서는 min값(A에서 min이면, B에서 max값)을 뽑아 곱해주면 된다. 이를 간단하게 구현하기위해 매개변수 A,B를 각각 Arrays.sort()로 정렬하고, for문 순회를 통해 A,B값을 곱해주면 된다.


올바른 괄호

📑 문4) 괄호가 바르게 짝지어졌다는 것은 '(' 문자로 열렸으면 반드시 짝지어서 ')' 문자로 닫혀야 한다는 뜻입니다. 예를 들어

  • "()()" 또는 "(())()" 는 올바른 괄호입니다.
  • ")()(" 또는 "(()(" 는 올바르지 않은 괄호입니다.

'(' 또는 ')' 로만 이루어진 문자열 s가 주어졌을 때, 문자열 s가 올바른 괄호이면 true를 return 하고, 올바르지 않은 괄호이면 false를 return 하는 solution 함수를 완성해 주세요.


제한사항

  • 문자열 s의 길이 : 100,000 이하의 자연수
  • 문자열 s는 '(' 또는 ')' 로만 이루어져 있습니다.

입출력 예

sanswer
()()true
(())()true
)()(true
(()(true

나의 풀이

package programmers;

import java.util.Stack;

public class CorrectParentheses {
	
	static boolean   solution(String s) {
        
		Stack<Character> stack = new Stack<>();
		
		for(char c : s.toCharArray()) {
			if(c == '(') {
				stack.push(c);
			} else if(c == ')' && !stack.isEmpty() && stack.peek()== '(') {
				stack.pop();
			}else {
				stack.push(c);
			}
			
		}
		
		return stack.isEmpty();
    }
	
	
	public static void main(String[] args) {
		solution(")()(");
	}
	

}

나의 생각

이 문제의 핵심은 괄호가 정상적인 상태면 true, 올바른 괄호가 아니면 false값을 리턴하는 로직구현이다. Stack 클래스를 사용한 방법으로, stack'(' 해당 괄호가 들어오면 stack에 추가한다. 그렇지않으면 c 가 ) 이며 !stack.isEmpty이며 stack의 최상단의 문자가 ( 이면 stack의 최상단의 문자를 제거한다. 그리고 이 경우도 아니라면 stack에 문자를 추가한다. 매개변수로 주어지는 )()( 문자를 예로들어 살펴보자.

현재 스택에 저장된 값은 위의 그림과 같다. )( ← 다음 올 문자는 ) 이므로, 현재문자가 )이고 스택이 비어있지않으며, 현재 스택의 최상단의 문자가 (이기 때문에, ( 문자를 제거한다. 이 로직을 실행하면 실제로는 스택에 )문자가 쌓이지는 않지만 () 가 제거되는 효과를 갖는다.

최종적으로 스택이 비어있지않기 때문에 false를 반환한다.

stack을 사용하지 않는 방법

package programmers;

public class CorrectParentheses {
	
	static boolean  solution(String s) {
        
		int cnt = 0;
		
		for(int i = 0; i < s.length(); i++) {
			if(s.charAt(i) == '(') {
				cnt++;
			}else if(s.charAt(i) == ')') {
				cnt--;
			}
			
			if(cnt < 0) {
				return false;
			}
		}
		return cnt == 0 ;
    }
	
	
	public static void main(String[] args) {
		solution(")()(");
	}
	

}

이진 변환 반복하기

📑 문5) 0과 1로 이루어진 어떤 문자열 x에 대한 이진 변환을 다음과 같이 정의합니다.

  • x의 모든 0을 제거합니다.
  • x의 길이를 c라고 하면, x를 "c를 2진법으로 표현한 문자열"로 바꿉니다.

예를 들어, x = "0111010"이라면, x에 이진 변환을 가하면 x = "0111010" -> "1111" -> "100" 이 됩니다.

0과 1로 이루어진 문자열 s가 매개변수로 주어집니다. s가 "1"이 될 때까지 계속해서 s에 이진 변환을 가했을 때, 이진 변환의 횟수와 변환 과정에서 제거된 모든 0의 개수를 각각 배열에 담아 return 하도록 solution 함수를 완성해주세요.


제한사항

  • s의 길이는 1 이상 150,000 이하입니다.
  • s에는 '1'이 최소 하나 이상 포함되어 있습니다.

입출력 예

sresult
110010101001[3,8]
01110[3,3]
1111111[4,1]

입출력 예 설명

입출력 예 #1

  • "110010101001"이 "1"이 될 때까지 이진 변환을 가하는 과정은 다음과 같습니다.
회차이진 변환 이전제거할 0의 개수0 제거 후 길이이진 변환 결과
111001010100166110
21101210
310111
  • 3번의 이진 변환을 하는 동안 8개의 0을 제거했으므로, [3,8]을 return 해야 합니다.

입출력 예 #1

  • "110010101001"이 "1"이 될 때까지 이진 변환을 가하는 과정은 다음과 같습니다.
회차이진 변환 이전제거할 0의 개수0 제거 후 길이이진 변환 결과
111001010100166110
21101210
310111
  • 3번의 이진 변환을 하는 동안 8개의 0을 제거했으므로, [3,8]을 return 해야 합니다.

입출력 예 #2

  • "01110"이 "1"이 될 때까지 이진 변환을 가하는 과정은 다음과 같습니다.
회차이진 변환 이전제거할 0의 개수0 제거 후 길이이진 변환 결과
1011102311
2110210
310111
  • 3번의 이진 변환을 하는 동안 3개의 0을 제거했으므로, [3,3]을 return 해야 합니다.

입출력 예 #3

  • "1111111"이 "1"이 될 때까지 이진 변환을 가하는 과정은 다음과 같습니다.
회차이진 변환 이전제거할 0의 개수0 제거 후 길이이진 변환 결과
1111111107111
21110311
3110210
310111
  • 4번의 이진 변환을 하는 동안 3개의 0을 제거했으므로, [4,1]을 return 해야 합니다.

나의 풀이

package programmers;

public class RepeatBinaryConversion {
	
	public static int[] solution(String s) {
        int[] answer = new int[2];
        
        StringBuilder sb = new StringBuilder(s);
        
        
        int cnt = 0; // Number Of Zeros To Remove
        int removeZero = 0;
        int LAR = 0; // Length After Removal
        int round = 0;
        
        while(!sb.toString().equals("1")) {
        	round ++;
        	for(int i = 0; i < sb.length(); i++) {
        		if(sb.charAt(i) == '0') {
        			sb.deleteCharAt(i);
        			i--;
        			cnt++;
        		}
        	}        	
        	LAR = sb.length();
        	removeZero += cnt;
        	cnt = 0;
        	sb.setLength(0);
        	sb.append(Integer.toBinaryString(LAR));
   
        	
        }
        	
        answer[0]= round;
        answer[1]= removeZero;        
        	
 
        return answer;
    }
	
	public static void main(String[] args) {
		solution("110010101001");
	}

}

나의 생각

  • "110010101001"이 "1"이 될 때까지 이진 변환을 가하는 과정은 다음과 같습니다.
회차이진 변환 이전제거할 0의 개수0 제거 후 길이이진 변환 결과
111001010100166110
21101210
310111

이것을 예로보면 최종적으로 리턴해야하는 값은 마지막 회차제거할 0의 갯수의 합이다. 이번 예를 보면 answer [3,8]을 리턴한다. 따라서 구성해야할 로직에는 회차를 기록할 int round, 제거할 0의 개수를 나타내는 int cnt, 0 제거후 길이를 나타내는 int LAR 그리고 제거할 0의 갯수의 합을 나타내는 int removeZero 변수가 필요하다. 어떤 수의 형태이든, 최종적으로 이진 변환의 결과의 값은 무조건 1을 나타내기때문에 그 결과가 1일때까지 while 문을 사용한다. StringBuilder의 선언 이유는 문자열의 크기와 문자열을 이루는 문자가 회차를 거듭하며 값이 변하기때문에 이를 능동적으로 컨트롤하기 쉬운 StringBuilder를 사용하였다. 핵심 로직은 다음과 같다.

while(!sb.toString().equals("1")) {
	round ++;
    for(int i = 0; i < sb.length(); i++) {
    	if(sb.charAt(i) == '0') {
        	sb.deleteCharAt(i);
            i--;
            cnt++;
        }
    }        	
    LAR = sb.length();
    removeZero += cnt;
    cnt = 0;
    sb.setLength(0);
    sb.append(Integer.toBinaryString(LAR));
       	
}

if(sb.charAt(i) == '0'은 문자열에서 '0'과 같으면 sb.deleteCharAt(i)로 해당 index에 해당하는 값을 제거하고, i--;를 통해 index 범위를 초과하지않도록 하고 cnt++를 통해 제거된 0을 개수를 카운팅한다. 모든 반복을 완료하면 sb.length의 값은Length After Removal(LAR)이 되고, 제거된 0의 개수를 담은 cnt를 removeZero에 더해준다. 그리고 cnt, sb.length로 값을 초기화해주고 0제거후 길이의 값이 다음 이진 변환의 결과로 sb값에 들어가게 된다. 즉, while문 반복동안 sb의 값이 1이 될때까지 무한반복한다.


다른 풀이

package programmers;

public class RepeatBinaryConversion2 {
	
	public static int[] solution(String s) {
	        
			int zeroCount = 0;
			int transformationCount = 0;
			
			StringBuilder sb = new StringBuilder(s);
			
			while(!sb.toString().equals("1")) {
				transformationCount++;
				int lengthBefore = sb.length();
				String afterZeroRemoved = sb.toString().replace("0", "");
				sb.setLength(0);
				sb.append(afterZeroRemoved);
				int lengthAfter = sb.length();
				zeroCount += (lengthBefore - lengthAfter);
				sb.setLength(0);
				sb.append(Integer.toBinaryString(lengthAfter));
			}
	        
			return new int[] {transformationCount, zeroCount};
	        
	    }
		
		public static void main(String[] args) {
			solution("110010101001");
		}

}
profile
HW + SW = 1

0개의 댓글