코딩 테스트/Level 2
18. 소수 찾기
컴닥
2020. 8. 1. 23:59
반응형
https://programmers.co.kr/learn/courses/30/lessons/42839
코딩테스트 연습 - 소수 찾기
한자리 숫자가 적힌 종이 조각이 흩어져있습니다. 흩어진 종이 조각을 붙여 소수를 몇 개 만들 수 있는지 알아내려 합니다. 각 종이 조각에 적힌 숫자가 적힌 문자열 numbers가 주어졌을 때, 종이 �
programmers.co.kr
파이썬
from itertools import permutations
def solution(numbers):
numbers_set = {int("".join(i)) for r in range(1, len(numbers)+1) for i in permutations(numbers, r)}
max_num = max(numbers_set)
a = [False, False] + [True] * (max_num - 1)
primes = set()
for i in range(2, max_num + 1):
if a[i]:
primes.add(i)
for j in range(2 * i, max_num + 1, i):
a[j] = False
return len(primes & numbers_set)
테스트 1 〉 통과 (0.61ms, 10.9MB)
테스트 2 〉 통과 (112.58ms, 20.8MB)
테스트 3 〉 통과 (0.07ms, 10.9MB)
테스트 4 〉 통과 (53.99ms, 16.6MB)
테스트 5 〉 통과 (837.15ms, 61.6MB)
테스트 6 〉 통과 (0.07ms, 10.8MB)
테스트 7 〉 통과 (0.61ms, 11MB)
테스트 8 〉 통과 (1416.37ms, 95.3MB)
테스트 9 〉 통과 (0.11ms, 10.9MB)
테스트 10 〉 통과 (169.07ms, 25.7MB)
테스트 11 〉 통과 (16.21ms, 12.5MB)
테스트 12 〉 통과 (9.39ms, 12MB)
리스트 컴프리헨션 내의 2중 for 문은 실전에선 애매합니다.
다시 보면 좀 혼란스럽습니다...
리턴 문에서 교집합 연산을 제거하고,
한 줄을 더 늘려 속도가 올렸습니다.
from itertools import permutations
def solution(numbers):
answer = 0
numbers_set = {int("".join(i)) for r in range(1, len(numbers)+1) for i in permutations(numbers, r)}
max_num = max(numbers_set)
a = [False, False] + [True] * (max_num - 1)
for i in range(2, max_num + 1):
if a[i]:
if i in numbers_set:
answer += 1
for j in range(2 * i, max_num + 1, i):
a[j] = False
return answer
테스트 1 〉 통과 (0.55ms, 10.9MB)
테스트 2 〉 통과 (113.78ms, 20.8MB)
테스트 3 〉 통과 (0.07ms, 10.9MB)
테스트 4 〉 통과 (50.82ms, 15.4MB)
테스트 5 〉 통과 (721.26ms, 61.5MB)
테스트 6 〉 통과 (0.06ms, 10.9MB)
테스트 7 〉 통과 (0.59ms, 10.9MB)
테스트 8 〉 통과 (1079.97ms, 95.5MB)
테스트 9 〉 통과 (0.12ms, 10.9MB)
테스트 10 〉 통과 (177.72ms, 25.7MB)
테스트 11 〉 통과 (15.29ms, 12.2MB)
테스트 12 〉 통과 (8.19ms, 11.4MB)
집합 자료형과 에라스토테네스의 채로 나름 최적화했지만..
다른 분의 코드를 보니... (와우~! 이 건 뭐지?)
코드량은 절반, 속도는 최대 2배가량 빠름~! ㄷㄷㄷㄷ
집합에서 요소를 바로 제거해주었네요.. 왜 이 생각을 못했을까..
from itertools import permutations
def solution(numbers):
numbers_set = {int("".join(i)) for r in range(1, len(numbers)+1) for i in permutations(numbers, r)}
numbers_set -= {0, 1}
for i in range(2, int(max(numbers_set) **0.5) + 1):
numbers_set -= set(range(2 * i, max(numbers_set) + 1, i))
return len(numbers_set)
테스트 1 〉 통과 (0.53ms, 11.1MB)
테스트 2 〉 통과 (73.84ms, 44.8MB)
테스트 3 〉 통과 (0.09ms, 11MB)
테스트 4 〉 통과 (49.31ms, 20.5MB)
테스트 5 〉 통과 (191.92ms, 146MB)
테스트 6 〉 통과 (0.07ms, 10.9MB)
테스트 7 〉 통과 (0.64ms, 11MB)
테스트 8 〉 통과 (528.21ms, 281MB)
테스트 9 〉 통과 (0.10ms, 10.9MB)
테스트 10 〉 통과 (338.50ms, 51.8MB)
테스트 11 〉 통과 (26.02ms, 14.5MB)
테스트 12 〉 통과 (4.88ms, 13.9MB)
GO
import (
"sort"
"strconv"
"strings"
)
func count(nums string) map[rune]int {
numCount := make(map[rune]int)
for _, v := range nums {
numCount[v]++
}
return numCount
}
func solution(numbers string) (rtn int) {
// numbers에서 사용된 숫자의 개수 카운트
numCount := count(numbers)
// 종이에서 나올 수 있는 최대값을 구함.
numStr := strings.Split(numbers, "")
sort.Sort(sort.Reverse(sort.StringSlice(numStr)))
max, _ := strconv.Atoi(strings.Join(numStr, ""))
// 에라토스테네스의 체
// true로 초기화하기 번거로우니, 반대로 소수아님 == true 으로함)
notPrimes := make([]bool, max+1)
notPrimes[0], notPrimes[1] = true, true
for i := 2; i <= max; i++ {
if notPrimes[i] { // 소수가 아닌 경우
continue
}
for j := i * 2; j <= max; j += i {
notPrimes[j] = true
}
success := true // 성공 여부를 확인할 체커
// 소수에서 사용된 숫자의 개수 카운트
primeCount := count(strconv.Itoa(i))
// 소수와 numbers의 사용 숫자 개수 비교
for k, primeV := range primeCount {
if numV, ok := numCount[k]; !ok || primeV > numV {
success = false
break
}
}
if success == true {
rtn++
}
}
return
}
테스트 1 〉 통과 (0.30ms, 7.23MB)
테스트 2 〉 통과 (29.96ms, 11.2MB)
테스트 3 〉 통과 (0.04ms, 7.16MB)
테스트 4 〉 통과 (15.79ms, 10.9MB)
테스트 5 〉 통과 (134.97ms, 15.6MB)
테스트 6 〉 통과 (0.05ms, 7.25MB)
테스트 7 〉 통과 (0.31ms, 7.32MB)
테스트 8 〉 통과 (213.74ms, 19.9MB)
테스트 9 〉 통과 (0.09ms, 7.15MB)
테스트 10 〉 통과 (41.91ms, 11.1MB)
테스트 11 〉 통과 (5.71ms, 9.4MB)
테스트 12 〉 통과 (3.63ms, 8.54MB)
느린 느낌이라.. 조금이나마 속도를 올리기 위해 몇 줄 추가해 보았습니다.
import (
"sort"
"strconv"
"strings"
)
func solution(numbers string) (rtn int) {
numCount := make(map[rune]int)
for _, v := range numbers {
numCount[v]++
}
numStr := strings.Split(numbers, "")
sort.Sort(sort.Reverse(sort.StringSlice(numStr)))
max, _ := strconv.Atoi(strings.Join(numStr, ""))
notPrimes := make([]bool, max+1)
notPrimes[0], notPrimes[1] = true, true
for i := 2; i <= max; i++ {
if !notPrimes[i] {
for j := i * 2; j <= max; j += i {
notPrimes[j] = true
}
}
}
for i, v := range notPrimes {
if v { // 소수가 아닌 경우
continue
}
success := true
primeCount := make(map[rune]int)
for _, primeNum := range strconv.Itoa(i) {
if _, ok := numCount[primeNum]; !ok {
success = false
break
}
primeCount[primeNum]++
}
if success == false {
continue
}
for primeNum, v := range primeCount {
if v > numCount[primeNum] {
success = false
break
}
}
if success == true {
rtn++
}
}
return
}
테스트 1 〉 통과 (0.11ms, 11MB)
테스트 2 〉 통과 (11.53ms, 10.4MB)
테스트 3 〉 통과 (0.03ms, 9.11MB)
테스트 4 〉 통과 (4.19ms, 9.59MB)
테스트 5 〉 통과 (44.55ms, 16.3MB)
테스트 6 〉 통과 (0.04ms, 9.33MB)
테스트 7 〉 통과 (0.12ms, 9.04MB)
테스트 8 〉 통과 (69.71ms, 19.5MB)
테스트 9 〉 통과 (0.07ms, 11.1MB)
테스트 10 〉 통과 (15.26ms, 11.1MB)
테스트 11 〉 통과 (1.59ms, 9.32MB)
테스트 12 〉 통과 (1.03ms, 9.14MB)
코드가 장황해졌지만 속도는 약 3배 정도 빨라졌습니다.
좀 더 깔끔하게 코드를 쓰고 싶지만 제 실력의 한계군요.
순열 없이 문제를 풀어보고 싶어서...
고 언어의 맵을 이용하면 될 것 같아 시도해 보았습니다만...
결과는... 그냥 그렇습니다.
C#
위 GO 코드를 C#에서 재작성해보았는데요..
using System.Collections.Generic;
using System.Linq;
public class Solution
{
public int solution(string numbers)
{
int answer = 0;
int max = int.Parse(string.Join("", numbers.OrderByDescending(c => c).ToArray()));
bool[] notPrimes = new bool[max + 1];
for (int i = 2; i <= max; i++)
{
if (notPrimes[i] == true)
continue;
for (int j = i * 2; j <= max; j += i)
notPrimes[j] = true;
}
Dictionary<char, int> numCount = new Dictionary<char, int>();
foreach (char c in numbers)
{
if (!numCount.ContainsKey(c))
numCount.Add(c, 1);
else
numCount[c]++;
}
for (int i = 2; i < notPrimes.Length; i++)
{
if (notPrimes[i] == true)
continue;
Dictionary<char, int> temp = new Dictionary<char, int>();
bool success = true;
foreach (char c in i.ToString())
{
if (!numCount.ContainsKey(c))
{
success = false;
break;
}
if (!temp.ContainsKey(c))
temp.Add(c, 1);
else
temp[c]++;
}
if (success == false)
continue;
foreach (char c in temp.Keys)
if (temp[c] > numCount[c])
{
success = false;
break;
}
if (success == true)
answer++;
}
return answer;
}
}
테스트 1 〉 통과 (20.80ms, 54.8MB)
테스트 2 〉 통과 (54.43ms, 57.5MB)
테스트 3 〉 통과 (20.30ms, 55MB)
테스트 4 〉 통과 (34.80ms, 57.2MB)
테스트 5 〉 통과 (113.10ms, 60.2MB)
테스트 6 〉 통과 (21.48ms, 54.8MB)
테스트 7 〉 통과 (20.24ms, 59.1MB)
테스트 8 〉 통과 (176.82ms, 62.2MB)
테스트 9 〉 통과 (20.66ms, 55MB)
테스트 10 〉 통과 (59.44ms, 59MB)
테스트 11 〉 통과 (24.23ms, 56.9MB)
테스트 12 〉 통과 (22.86ms, 54.9MB)
순열을 이용하니 코드량은 많이 주네요...
using System;
using System.Collections.Generic;
using System.Linq;
public class Solution
{
static List<int> numberList = new List<int>();
public int solution(string numbers)
{
List<int> primeList = new List<int>();
for (int i = 1; i <= numbers.Length; i++)
Perm(numbers.ToCharArray(), 0, numbers.Length, i);
numberList = numberList.Distinct().ToList();
int max = numberList.Max();
bool[] notPrimes = new bool[max + 1];
for (int i = 2; i <= max; i++)
{
if (notPrimes[i] == false)
primeList.Add(i);
for (int j = i * 2; j <= max; j += i)
notPrimes[j] = true;
}
return Enumerable.Intersect(numberList, primeList).Count();
}
public static void Perm(char[] arr, int depth, int n, int k)
{
if (depth == k)
{
numberList.Add(int.Parse(string.Join("", arr.Take(k))));
return;
}
for (int i = depth; i < n; i++)
{
char temp = arr[i];
arr[i] = arr[depth];
arr[depth] = temp; Perm(arr, depth + 1, n, k);
temp = arr[i];
arr[i] = arr[depth];
arr[depth] = temp;
}
}
}
테스트 1 〉 통과 (19.33ms, 56.7MB)
테스트 2 〉 통과 (40.16ms, 56MB)
테스트 3 〉 통과 (18.02ms, 57MB)
테스트 4 〉 통과 (29.80ms, 52.6MB)
테스트 5 〉 통과 (155.72ms, 67.7MB)
테스트 6 〉 통과 (19.15ms, 58.5MB)
테스트 7 〉 통과 (19.73ms, 54.7MB)
테스트 8 〉 통과 (275.99ms, 78.7MB)
테스트 9 〉 통과 (19.53ms, 54.9MB)
테스트 10 〉 통과 (45.78ms, 58.4MB)
테스트 11 〉 통과 (22.18ms, 57.1MB)
테스트 12 〉 통과 (19.97ms, 56.9MB)
하지만 속도 어쩔....
처음 어느 분의 파이썬 코드처럼 효율적으로 정리하는 방법을 찾아야 할 것 같은데....
그건.. 다른 분들의 풀이를 참고하시길 바라며..
반응형