TIL 17 -코드 가타:
- 하샤드 수
- 문제
양의 정수 x가 하샤드 수이려면 x의 자릿수의 합으로 x가 나누어져야 합니다. 예를 들어 18의 자릿수 합은 1+8=9이고, 18은 9로 나누어 떨어지므로 18은 하샤드 수입니다. 자연수 x를 입력받아 x가 하샤드 수인지 아닌지 검사하는 함수, solution을 완성해주세요.
제한 조건: x는 1 이상, 10000 이하인 정수입니다.- 풀이
class Solution {
public boolean solution(int x) {
int x1 = 0; // x의 자릿수 합을 저장할 변수
boolean answer = false; // 기본적으로 false를 설정
// 정수 x를 문자열로 변환하여 각 자리수를 확인
String s = String.valueOf(x);
// 문자열의 각 문자를 숫자로 변환하여 자릿수 합 계산
for (int i = 0; i < s.length(); i++) {
x1 = Character.getNumericValue(s.charAt(i)) + x1;
}
// x가 자릿수 합(x1)으로 나누어 떨어지면 true 설정
if (x % x1 == 0) {
answer = true;
}
return answer; // 최종 결과 반환
}
}
- 변수를 초기화합니다
- x를 문자열로 변환하여 각 자릿수를 쉽게 가져올 수 있도록 합니다 .
- 문자열의 각 문자를 char로 가져와 숫자로 변환한 후 더합니다.
- x가 자릿수 합 x1로 나누어 떨어지면 true 반환하여 하샤드 수 판별합니다
- 결과를 반환합니다.
- 트러블 슈팅(개선점 및 헷갈렸던 부분)
1. Character.getNumericValue(s.charAt(i)))는 문자를 숫자로 변환해주는 변환하는 중요한 역할을 하는데 맨처음에는 String에 Interge.valueOf()를 적용하는 것처럼 진행하려고 하였지만, 실패하야 Character.getNumericValue
(s.charAt(i))) 적용하였다.
2. 정수를 직접 연산하여 푸는방식으로 위에서 복잡한 개념들이 필요가 없어진다. 그러므로 좀더 직관적이게 작동원리를 파악할 수 있지 않은가 싶다.
class Solution {
public boolean solution(int x) {
int sum = 0;
int num = x;
// 자릿수 합 계산 (문자열 변환 없이 처리)
while (num > 0) {
sum += num % 10; // 끝자리 숫자 더하기
num /= 10; // 끝자리 제거
}
// 하샤드 수 여부 판단 후 반환
return x % sum == 0;
}
}
정수 제곱근 판별
- 문제
임의의 양의 정수 n에 대해, n이 어떤 양의 정수 x의 제곱인지 아닌지 판단하려 합니다.
n이 양의 정수 x의 제곱이라면 x+1의 제곱을 리턴하고, n이 양의 정수 x의 제곱이 아니라면 -1을 리턴하는 함수를 완성하세요.
- 풀이
class Solution {
public long solution(long n) {
long answer=-1;
for (long i=1; i<=n; i++){
if(((n/i))== i&&(n%i==0)){
answer=(i+1)*(i+1);
break;
}
}
return answer;
}
}
- answer 변수에 기본값 -1을 설정합니다.
- i를 1부터 n까지 증가시키면서 반복합니다.
- n을 i로 나눈 값이 i와 같고, 나머지가 0이면 i가 n의 제곱근이라는 뜻입니다.
- 정수 제곱근을 찾은 경우 다음 제곱수 반환합니다
- 반복문 종료합니다
- 트러블 슈팅(개선점 및 헷갈렸던 부분)
1. n을 i로 나눈 값이 i와 같고, 나머지가 0이면 i가 n의 제곱근이라는 뜻입니다.에서 나머지를 넣지않으면 101같은 숫자에서 오류가 발생하여 질문을 통하여 해결한 부분이다. 정확한 원인은 파악해야하는 부분이다.
2 . 시간 복잡도 개선
기존 코드는 O(n) 시간 복잡도에 따라n이 클 경우 매우 비효율적이지만, 아래와 같이 구현한다면 O(1) 시간 복잡도 가 실현 되어 훨씬 빠른 로직과 직관적인 동작을 한다.
class Solution {
public long solution(long n) {
long sqrt = (long) Math.sqrt(n); // n의 제곱근을 구함
if (sqrt * sqrt == n) { // 제곱수인지 확인
return (sqrt + 1) * (sqrt + 1); // (sqrt+1)의 제곱 반환
}
return -1; // 제곱수가 아니면 -1 반환
}
}
콜라츠 추측
- 문제
1937년 Collatz란 사람에 의해 제기된 이 추측은, 주어진 수가 1이 될 때까지 다음 작업을 반복하면, 모든 수를 1로 만들 수 있다는 추측입니다. 작업은 다음과 같습니다.
1-1. 입력된 수가 짝수라면 2로 나눕니다.
1-2. 입력된 수가 홀수라면 3을 곱하고 1을 더합니다.
2. 결과로 나온 수에 같은 작업을 1이 될 때까지 반복합니다.
예를 들어, 주어진 수가 6이라면 6 → 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1 이 되어 총 8번 만에 1이 됩니다. 위 작업을 몇 번이나 반복해야 하는지 반환하는 함수, solution을 완성해 주세요. 단, 주어진 수가 1인 경우에는 0을, 작업을 500번 반복할 때까지 1이 되지 않는다면 –1을 반환해 주세요.
- 풀이
class Solution {
public int solution(long num) {
int stack = 0; // 반복 횟수를 저장할 변수
// 주어진 숫자가 1이 아닐 때까지 반복
while(num != 1){
// 반복 횟수가 500을 초과하면 -1을 반환하고 종료
if(stack == 500){
stack = -1;
break;
}
// 짝수일 경우 2로 나누기
if(num % 2 == 0){
num = num / 2;
}
// 홀수일 경우 3을 곱하고 1을 더하기
else{
num = (num * 3) + 1;
}
// 연산 횟수 증가
stack += 1;
}
// 최종적으로 연산 횟수를 반환
return stack;
}
}
- stack 변수를 이용해 연산 횟수를 저장합니다.
- while(num != 1) 루프를 통해 주어진 숫자가 1이 될 때까지 반복합니다.
- 만약 반복 횟수가 500을 초과하면 -1을 반환하고 종료합니다.
- 숫자가 짝수이면 num / 2, 홀수이면 (num * 3) + 1을 수행합니다.
- 연산 횟수(stack)를 1 증가시키고 다시 검사합니다.
- 최종적으로 stack 값을 반환합니다.
- 트러블 슈팅(개선점 및 헷갈렸던 부분)
1. (int) num으로 구현 하여서 바운드가 넘어가는 문제가 발생 하였고 이를(long) num으로 구현함으로 바운드 문제해결하였다. -> 범위에 대해서 언제나 확인해야 한다는 점을 잊으면 안된다.
2. 타인의 코드를 봤을 경우, 삼항연산자가 많이 보였다.하지만 삼항연산자는 가독성이 비교적 떨어져 현장에 선호되지 않으니, 사용하지 않도록 주의해야한다.
자연수 뒤집어 배열로 만들기
- 문제
자연수 n을 뒤집어 각 자리 숫자를 원소로 가지는 배열 형태로 리턴해주세요. 예를들어 n이 12345이면 [5,4,3,2,1]을 리턴합니다.
제한 조건: n은 10,0이하인 자연수입니다. 10,000,000,000이하인 자연수입니다.- 풀이
class Solution {
public int[] solution(long n) {
// long 타입의 숫자를 문자열로 변환
String an = String.valueOf(n);
// 문자열을 한 글자씩 잘라서 리스트로 변환
List<String> ans = new ArrayList<>(Arrays.asList(an.split("")));
// 리스트를 뒤집음 (숫자의 자릿수를 뒤집기 위함)
Collections.reverse(ans);
// 정수 배열을 생성 (원본 문자열 길이와 동일한 크기)
int[] answer = new int[an.length()];
// 리스트에 저장된 문자열을 정수(int)로 변환하여 배열에 저장
for (int i = 0; i < ans.size(); i++) {
answer[i] = Integer.valueOf(ans.get(i));
}
// 최종 결과 반환
return answer;
}
}
- 입력값 n을 문자열로 변환하여 각 자리 숫자에 쉽게 접근할 수 있도록 합니다.
- split("")을 사용하여 문자열을 한 글자씩 분리하여 리스트로 변환합니다.
- Arrays.asList()로 변환 후, ArrayList로 감싸서 가변 리스트로 만듭니다..
- 리스트를 뒤집어서 자릿수를 거꾸로 정렬합니다.
- 원본 문자열의 길이만큼 크기를 갖는 int 배열을 생성합니다.
- 리스트의 각 요소를 Integer.valueOf()를 사용해 정수로 변환 후 배열에 저장합니다.
- 결과 반환합니다
- 트러블 슈팅(개선점 및 헷갈렸던 부분)
class Solution {
public int[] solution(long n) {
// 숫자의 자릿수를 구하기 위해 문자열 변환
String s = Long.toString(n);
// 정수 배열 생성
int[] answer = new int[s.length()];
// 숫자의 자릿수를 뒤집어서 배열에 저장
for (int i = 0; i < s.length(); i++) {
answer[i] = s.charAt(s.length() - 1 - i) - '0';
}
return answer;
}
}
- 숫자를 문자열로 변환하여 자릿수를 직접 처리하는 방식으로 최적화
- charAt()과 '0'을 빼는 방식으로 변환 속도 개선
- 더 빠르고 간결한 코드로 최적화
위 코드 타인의 코드이다. 최적화가 잘된 코드이다 이처럼 구태여 복잡한 코드를 선택하기 보다는 기본의 이용이 중요하게 느껴진다. 내일(03.07)이면 다시 새로운 과제를 진행할텐데, 지금 접한 코드들의 내용도 중요하지만,기본을 잊지말자라는 생각을 가지게 된다.
내일: 과제해석 및 순서에 맞게 진행