프로그래머스 문제이다.
소인수분해 관련 문제이다.
n값이 주어지면 소인수를 배열에 담아서 return하는 문제였다.
해결 방법을 대강 짜봤는데
for문을 통해서 i를 순차적으로 키워가며 나눠서 배열에 담아주면 될 것 같았다. 예외사항으로 소인수에 1과 자기 자신은 포함이 안되므로 i를 2부터 시작해야하는 점.
그리고 n값이 2일 경우 [2]를 return해주어 예외사항을 넘겼다.
function solution(n) {
let arr = [];
if(n === 2){
return [2]
}
for(let i = 2; i <= n; i++){
if(n%i === 0){
n = n/i
arr.push(i)
}
}
return arr
이렇게 작성을 하니 예제 코드는 성공했으나 특정 케이스에 대해서 오류가 발생했다.
상황을 살펴보았는데 i부터 순차적으로 키워가며 push를 해준 결과 앞에서 이미 지나가버린 i값에 해당하는 숫자가 다시 등장할 경우를 처리하지 못하였다.
그래서 저렇게 나온 arr배열을 이번에는 map을 사용해서 다시 나누어서 배열을 만들어 주었다.
let a = arr[0]
let arr2 = arr.filter(function(m, i){
return m%arr[0] !== 0
})
arr2.unshift(a)
오류가 발생했던 케이스들 대부분이 해결되었으나
아직도 하나의 케이스가 성공을 하지 못했다...
팀원들과 이리저리 고민을 하다가 해결되지 않아서 방식을 바꿔보았다.
function solution(n) {
let arr = [];
let i = 2
if(n === 2){
return [2]
}
while(n >= 2){
if(n%i === 0){
arr.push(i)
n = n/i
}else{
i++
}
}
let l = arr.length
let arr2 = []
for(let i = 0; i < l; i++){
if(arr[i] !== arr[i+1]){
arr2.push(arr[i])
}
}
return arr2
}
두 가지의 해결 방법이 나왔는데 우선 이 방법은
for문이 아니라 while으로 돌려서 앞서서 for문으로 돌렸을 때 나타난 덜 나눠진 수가 존재하지 않는 상황을 만들었다.
(n%i===0일 경우 나눈값을 push해주고 그렇지 않을때만 i++을 하여서 2, 3 ... 순서로 안나눠질때까지 반복하여 나눈 후 나눠지지 않는 시점에서 다음 수로 넘어가는 방식)
그 후 나온 배열 값에서 중복된 값을 제거해주었다.
처음에는 length와 arr를 직접 가공하는 방식을 취했는데
splice나 여타 메소드가 사용되면서 arr배열의 길이나 구조 자체가 for문을 돌면서 바뀌는 바람에 제대로 된 값이 나오질 않았다.
그래서 let l = arr.length로 let arr2 = arr으로 길이와 arr의 정보값을 담은 arr2 배열을 선언해주고 arr2를 splice하였다.
이제 arr배열 자체를 건들지 않으므로 문제가 해결될 것이라고 생각했으나 이전과 같은 상황이 반복되었다.
맞다.. 분명히 전에 배웠던 배열의 주소 저장방식과 관련된 내용이었는데 해당 부분을 간과해 버렸다.
arr2를 선언하고 arr값을 복사한 후 arr2만 가공하면 arr은 그대로 유지될 것 처럼 보이지만 사실 값을 별개로 저장한 것이 아니라 arr이 쓰고있던 주소의 값을 복사해 온 것이다. 따라서 arr2 배열의 내부 값을 수정하면 arr역시 따라서 수정되는 상황이었다.
그래서 최종적으로 선택한 방식은 arr2에 빈 배열을 할당하고 조건에 충족하는 것을 push방식으로 넣어서 해결하였다.
간단해보였는데 너무 멀리 돌아온 것 같다...
좀 더 간편한 다른 방식의 해결책도 있었다.
Set을 이용하는 방법인데,
Set의 경우 중복된 값은 하나로 겹쳐지는 성질을 가지고 있다.
(2,3,3,4의 값을 순서대로 저장할 경우 2,3,4만 남는다.)
function solution(n) {
let arr = new Set;
let i = 2
if(n === 2){
return [2]
}
while(n >= 2){
if(n%i === 0){
arr.add(i)
n = n/i
}else{
i++
}
}
return [...arr]
}
뼈대는 그대로 사용하였다. 다만 arr에 빈 배열을 할당하지 않고 new Set으로 새로 Set을 할당해주었다.
그 후 while문 안에서 arr.add로 Set내부에 해당 값을 저장해주었다. 저장 과정에서 자연스럽게 중복값은 탈락하므로 따로 중복된 값을 처리해주는 과정도 불필요해주었다.
마지막으로 return 값은 배열로 내보내야하므로 스프레드 연산자를 활용하여 [...arr]로 써주었다.
이렇게 Set을 활용하니 코드의 가독성이 매우 좋아졌다.