목차
문제
- int 배열이 주어졌을 때, 각 원소의 자릿수가 짝수개인 원소의 개수를 구하시오.
- 예시
-
Input: nums = [12,345,2,6,7896] Output: 2
-
Input: nums = [555,901,482,1771] Output: 1
-
- 제약조건
- 1 <= nums.length <= 500
- 1 <= nums[i] <= 105
문제 풀이
풀이 1 : 숫자 추출
- 풀이
- 7329 = 7*(10^3) + 3*(10^2) + 2*(10^1) + 9*(10^0) 방식으로 분리하여 자릿수를 계산하는 방식으로 문제해결
- 코드
-
class Solution: # Helper function to check if the number of digits is even def hasEvenDigits(self, num: int) -> bool: digit_count = 0 while num: digit_count += 1 num //= 10 return digit_count & 1 == 0 def findNumbers(self, nums: List[int]) -> int: # Counter to count the number of even digit integers even_digit_count = 0 for num in nums: if self.hasEvenDigits(num): even_digit_count += 1 return even_digit_count
-
- 시간복잡도 : O(NlogM)
- 하나의 숫자에 대해서 hasEvenDigits 함수의 시간복잡도 O(logM)가 됩니다. (정확히는 밑이 10인 로그)
- M은 num 중 가능한 최대 숫자입니다.
- 모든 숫자에 대해 적용하므로 O(NlogM)입니다.
- 하나의 숫자에 대해서 hasEvenDigits 함수의 시간복잡도 O(logM)가 됩니다. (정확히는 밑이 10인 로그)
풀이 2 : 문자열로 변환
- 풀이
- 숫자를 문자열로 변환한 뒤 len 함수를 통해 길이를 체크하는 방식입니다.
- 코드
-
class Solution: def findNumbers(self, nums: List[int]) -> int: # Counter to count the number of even digit integers even_digit_count = 0 for num in nums: # Convert num to string and find its length length = len(str(num)) if length % 2 == 0: even_digit_count += 1 return even_digit_count
-
- 시간복잡도 : O(NlogM)
- 하나의 숫자에 str로 변환하는 시간복잡도는 O(logM)입니다. (정확히는 밑이 10인 로그)
- M은 num 중 가능한 최대 숫자입니다.
- 길이를 체크하는 len 함수의 시간복잡도는 O(1)입니다.
- 따라서 모든 숫자에 대해 적용하므로 O(NlogM)입니다.
- 하나의 숫자에 str로 변환하는 시간복잡도는 O(logM)입니다. (정확히는 밑이 10인 로그)
풀이 3 : 로그 사용
- 풀이
- 10^k <= x < 10^(k+1)이라고 한다면 k <=log_10(x)<k+1 이 됩니다.
- 10^k <= x < 10^(k+1)의 자릿수의 개수는 k+1입니다. 예를 들어 4521의 경우 4*10^3+5*10^2+2*10^1+1*10^0 이므로 10^3 보다 크고 10^4보다 작습니다. 여기서 4521의 자릿수의 개수는 4자리입니다.
- 즉, 밑이 10인 로그를 취한 값에 1을 더하면 전체 자릿수가 나오게 됩니다.
- 코드
-
class Solution: def findNumbers(self, nums: List[int]) -> int: # Counter to count the number of even digit integers even_digit_count = 0 for num in nums: # Compute the number of digits in num digit_count = int(math.floor(math.log10(num))) + 1 if digit_count % 2 == 0: even_digit_count += 1 return even_digit_count
-
- 시간복잡도 : O(NlogM)
- 하나의 숫자에 log를 적용하는 시간 복잡도는 Olog(M)입니다. (정확히는 밑이 10인 로그)
- M은 num 중 가능한 최대 숫자입니다.
- math.floor의 경우 버림이므로 O(1)입니다.
- 따라서 모든 숫자에 대해 적용하므로 O(NlogM)입니다.
- 하나의 숫자에 log를 적용하는 시간 복잡도는 Olog(M)입니다. (정확히는 밑이 10인 로그)
풀이 4 : 제약 분석
- 풀이
- 문제에서 숫자의 범위는 1부터 10^5 까지였습니다. 따라서 단순하게 그냥 x가 1 <=x <10 일 경우 홀수개, 10 <=x <100일 경우, 짝수개, 이런 식으로 나아가게 되면 별다른 함수 실행 없이 O(1)만에 처리가 가능합니다.
- 코드
-
class Solution: def findNumbers(self, nums: List[int]) -> int: # Counter to count the number of even digit integers even_digit_count = 0 for num in nums: if (num >= 10 and num <= 99) or (num >= 1000 and num <= 9999) or (num == 100000): even_digit_count += 1 return even_digit_count
-
- 시간복잡도 : O(N)
- 제약조건을 잘 이용하면 자릿수가 홀수개인지 짝수개인지 판별하는 것이 O(1)만에 끝나버리게 됩니다.
- 따라서 전체 숫자에 대한 시간복잡도는 O(N)이 될 것입니다.
알게 된 내용
- 홀수 짝수 비교 시 %2를 이용할 수도 있지만 &1을 이용할 수도 있습니다.
- 홀수일 경우 이진수로 표현하면 반드시 마지막 숫자는 1일 것입니다.
- 따라서 홀수&1== 1이 됩니다. 마찬가지로 짝수 &1==0입니다.
- 숫자를 문자로 변환하는 시간복잡도
- O(logM) (정확히는 밑이 10인 로그)
- M은 num 중 가능한 최대 숫자입니다.
- O(logM) (정확히는 밑이 10인 로그)
- log함수의 시간복잡도
- 숫자 num 1개가 있더라도 log(num)을 하게 되면 이것의 시간복잡도는 O(logM)이 될 것입니다.
- M은 num 중 가능한 최대 숫자입니다.
- 아래의 단순화한 log 연산과정만을 보더라도 결국 해당 밑을 계속 제곱하면서 만족하는 로그의 값을 찾아나가는 것입니다. 따라서 math.log 함수의 시간복잡도는 log(num)만큼의 시간이 소요될 것입니다.
- 단순화한 log 연산과정
- 문제: 숫자 M에 대한 로그 값을 2의 거듭제곱 형태로 근사하려고 합니다. 즉, 2^x ≈ M인 x 값을 찾으려고 합니다.
- 단계별 접근:
- x의 시작 값을 0으로 설정합니다.
- 2^x가 M보다 작은 동안, x를 1씩 증가시킵니다.
- 2^x가 M을 초과하거나 같아지면, 그때의 x 값이 M에 대한 로그 값의 근사치입니다.
- 숫자 num 1개가 있더라도 log(num)을 하게 되면 이것의 시간복잡도는 O(logM)이 될 것입니다.
출처
'Algorithm > 리트코드(LeetCode)' 카테고리의 다른 글
[LeetCode] Check If N and Its Double Exist (0) | 2024.04.08 |
---|---|
[LeetCode] Remove Duplicates from Sorted Array (0) | 2024.04.08 |
[LeetCode] Remove Element (0) | 2024.04.08 |
[LeetCode] Merge Sorted Array (0) | 2024.04.08 |
[LeetCode] Squares of a Sorted Array (1) | 2024.04.07 |