TIL: 2022-05-16 알고리즘 day3

김하연·2022년 5월 16일
0

TIL: Today I Leaned

목록 보기
7/26

1. 완주하지 못한 선수

수많은 마라톤 선수들이 마라톤에 참여하였습니다. 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다.

마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요.

  • 마라톤 경기에 참여한 선수의 수는 1명 이상 100,000명 이하입니다.
  • completion의 길이는 participant의 길이보다 1 작습니다.
  • 참가자의 이름은 1개 이상 20개 이하의 알파벳 소문자로 이루어져 있습니다.
  • 참가자 중에는 동명이인이 있을 수 있습니다.

예시

입출력 예

participant											completion									return
["leo", "kiki", "eden"]								["eden", "kiki"]							"leo"
["marina", "josipa", "nikola", "vinko", "filipa"]	["josipa", "filipa", "marina", "nikola"]	"vinko"
["mislav", "stanko", "mislav", "ana"]				["stanko", "ana", "mislav"]					"mislav"

내가 작성한 solution.js

function solution(participant, completion) {
    var answer = '';
    for(let i = 0; i < participant.length; i++) {
        for(let j=0; j<completion.length; j++){
            if(participant[i] === completion[j])  {
                participant.splice(i, 1);
                completion.splice(j, 1);
                i--;
                j--;
            }
        }
    }
    return answer;
}
테스트 1 〉	통과 (0.07ms, 30.3MB)
테스트 2 〉	통과 (0.09ms, 30.2MB)
테스트 3 〉	통과 (5.37ms, 32.5MB)
테스트 4 〉	통과 (19.65ms, 32.7MB)
테스트 5 〉	통과 (16.86ms, 32.5MB)

위 코드는 정확성 테스트는 통과했지만 효율성 테스트에서 모두 시간초과로 실패했다.
우선 두 배열을 비교해서 participant 배열에 들어있는 요소가 completion 배열의 요소와 겹칠 경우 해당 요소를 participant 배열에서 splice를 활용해 제거하는 방식으로 풀어보려고 했다.
제거한 후에는 participant의 아이템 숫자가 줄었으므로 i--를 적용했고, 방금 삭제된 요소가 completion 배열에서도 제거되어야 동명이인을 찾을 수 있을 것 같아서 completion배열에서도 해당 요소를 제거하고 j--도 함께 적용했다.

그러나... 2중 for문을 사용해서 그런지 전부다 시간초과로 효율성 테스트 실패 ㅜ.ㅜ

머리를 아무리 굴려도 해결이 안돼서 결국 다른 사람들의 풀이를 찾아봤다.
그 중 내가 시도한 방법에 추가로 적용해 해결할 수 있을 것 같은 풀이를 참고했다.

function solution(participant, completion) {
    var answer = '';
    participant.sort();
    completion.sort();
    
    for(let i=0; i<participant.length; i++){
        if(participant[i] !== completion[i]){
            answer = participant[i];
            break;
        }
    }
    return answer;
}
테스트 1 〉	통과 (0.05ms, 30.3MB)
테스트 2 〉	통과 (0.05ms, 29.9MB)
테스트 3 〉	통과 (0.29ms, 29.8MB)
테스트 4 〉	통과 (0.60ms, 30.3MB)
테스트 5 〉	통과 (0.57ms, 30.2MB)

배열에 sort()를 사용해 요소들을 순서대로 재정렬 한 후에, for문을 돌면서 participant, completion배열이 일치하지 않을 경우 for문을 종료한 후 해당 요소를 answer로 리턴시키는 방법이다.
배열을 sort()를 사용해 먼저 재정렬 시키는 방법이 있었다니.. 두 배열을 비교 할 때에는 진짜 야무지게 사용할 수 있는 방법같다!

추가로, 일치하지 않는 요소를 찾아냈을 경우 for문을 종료시키기 위해 break 명령어를 사용했는데 return, break 의 차이점을 확실히 이해하기 위해 정보를 찾아봤다.

  • break
    가장 가까이에 있는 반복문을 탈출하는 명령어.
    Loop가 모두 끝나지 않았어도 break 명령어를 사용할 경우 해당 for문이 종료된다.

  • return
    return이 쓰여진 함수 안에서 탈출하는 명령어.
    for문 안에서 return을 실행할 경우 바로 그 for문을 포함한 함수의 밖으로 탈출하게 된다.
    for문 뿐만이 아니라 해당 return의 뒷줄에 더 많은 코드들이 있다고 해도 해당 코드들은 실행되지 않고 함수 밖으로 벗어나게 된다.

  • continue
    해당 반복문 안에서 현재 loop를 중단하고 다음 loop를 실행시킨다.




2. 이상한 문자 만들기

문자열 s는 한 개 이상의 단어로 구성되어 있습니다. 각 단어는 하나 이상의 공백문자로 구분되어 있습니다. 각 단어의 짝수번째 알파벳은 대문자로, 홀수번째 알파벳은 소문자로 바꾼 문자열을 리턴하는 함수, solution을 완성하세요.

  • 문자열 전체의 짝/홀수 인덱스가 아니라, 단어(공백을 기준)별로 짝/홀수 인덱스를 판단해야합니다.
  • 첫 번째 글자는 0번째 인덱스로 보아 짝수번째 알파벳으로 처리해야 합니다.

예시

입출력 예

s					return
"try hello world"	"TrY HeLlO WoRlD"

내가 작성한 solution.js

function solution(s) {
    var answer = '';
    let result = s.split('').reduce((acc,cur,idx)=>{
        return acc = acc + (idx%2 ? cur.toLowerCase() : cur.toUpperCase());
    },'');
    return answer = result;
}

이렇게 작성해서 코드 실행하면 성공이라고 뜨는데, 제출하기 눌러보면 정확성이 18.8/100 밖에 안나와서 대체 이게 뭐가 문제인가를 한참 고민했다...
내가 생각하지 못한 변수가 있나? 하고 임의로 텍스트에 공백 엄청 많이 넣어서 테스트도 해보고 이상한 글자를 써보고 아무리 별짓을 다 해봐도 원인을 못찾았는데..
문제를 잘못 이해한게 문제였다.. 계속 깨닫는거지만, 이건 문제를 푸는것도 중요하지만 그 전에 문제를 이해를 잘 했느냐가 진짜진짜 중요한 것 같다.
나는 텍스트 내의 모든 공백까지 인덱스에 포함하여 전체적인 흐름이 홀/짝/홀/짝... 으로 변환되면 되는 줄 알았는데, 각 단어들 안에서 홀/짝의 패턴을 이뤄야 하는거였다...ㅜㅜ

function solution(s) {
    var answer = '';
    
    var result = s.split(' ').map((word,idx)=>{
        let transfered = word.split('').map((letter,idx)=>{
            return (idx%2) ? letter.toLowerCase() : letter.toUpperCase();
        })
        return transfered.join('');
    })
    return answer = result.join(' ');
}

그렇게 해서 다시 작성한 코드.
드디어 통과!!!!!!!!
문장을 각 단어별로 나누고, 그 단어들을 또 각 글자별로 나누어야 하므로 콜백함수를 적용하여 새로운 배열을 반환하는 map을 이용하면 좋겠다고 생각했다.
s를 split(' ') 하여 공백 기준으로 각 단어들을 나누고, 그 안에서 또 각 단어를 split('') 하여 한글자씩 나눠 돌렸다. 글자의 index가 홀수일 경우 대문자로, 짝수일 경우 소문자로 변형된 값을 return하고 return된 글자들을 join('')으로 하나의 단어로 다시 묶어 반환하였다. 그리고 단어들이 반환된 값을 또 다시 join(' ')처리하여 단어들 사이에 공백을 추가해 하나의 문장으로 변환하였다.




3. 자릿수 더하기

자연수 N이 주어지면, N의 각 자릿수의 합을 구해서 return 하는 solution 함수를 만들어 주세요.
예를들어 N = 123이면 1 + 2 + 3 = 6을 return 하면 됩니다.


예시

입출력 예

N	answer
123	6
987	24

내가 작성한 solution.js

function solution(s) {
    var answer = 0;
    answer = n.toString().split('').reduce((cur,acc)=>{
        return cur = cur + (acc/1);
    },0)
    return answer;
}

이건 결국 모든 수의 합을 더하면 되는 문제이길래, String 형태로 들어온 s를 string형태로 변환 후 split을 해서 배열에 담은다음에 reduce함수로 모든 요소들을 순서대로 더해주었다.




4. 자연수 뒤집어 배열로 만들기

자연수 n을 뒤집어 각 자리 숫자를 원소로 가지는 배열 형태로 리턴해주세요. 예를들어 n이 12345이면 [5,4,3,2,1]을 리턴합니다.

  • n은 10,000,000,000이하인 자연수입니다.

예시

입출력 예

n		return
12345	[5,4,3,2,1]

내가 작성한 solution.js

function solution(n) {
    var answer = [];
    let arr = n.toString().split('');
    for(let i=arr.length-1; i >= 0; i--){
        answer.push(Number(arr[i]));
    }
    
    return answer;
}

변수에 담겨있는 숫자들을 거꾸로 순서를 뒤집기만 하면 되는 문제길래 우선 string을 쪼개서 한글자씩 배열에 담았고, 그 배열을 for문을 돌려서 가장 뒤에 있는 글자부터 담기도록 했다.
보통 for문은 i를 올리는 식으로 활용을 많이하지만, 이 경우 가장 뒤에있는 index부터 필요하기에 i값을 줄이는 방식으로 구현하였다.



5. 정수 제곱근 판별

임의의 양의 정수 n에 대해, n이 어떤 양의 정수 x의 제곱인지 아닌지 판단하려 합니다.
n이 양의 정수 x의 제곱이라면 x+1의 제곱을 리턴하고, n이 양의 정수 x의 제곱이 아니라면 -1을 리턴하는 함수를 완성하세요.

예시

입출력 예

n		return
121		144
3		-1

내가 작성한 solution.js

function solution(n) {
    var answer = 0;
    return answer = Number.isInteger(Math.sqrt(n)) ? Math.pow((Math.sqrt(n) + 1),2) : -1;
}

이 문제는 제곱근과 거듭제곱 값을 계산해주는 함수가 있다는 것만 얼핏 기억나서, 검색해서 해결한 문제이다.

   Math.pow([대상 숫자], [거듭제곱 횟수]); // 거듭제곱 값 구하는 함수
   Math.sqrt([대상 숫자]); // 제곱근 값 구하는 함수

이미 이렇게 완벽한 함수가 존재하는게 너무 다행이라는 생각이 들었다 ㅠㅠ
위 함수 사용 방식을 참고하여 숫자를 제곱근 구하는 식에 넣었을 때, 정수로 떨어진다면 어떤 숫자의 제곱인 것이고 정수가 아니라면 어떠한 숫자의 제곱이 아닌것으로 판단하여 구분하였다.




6. 정수 내림차순으로 배치하기

함수 solution은 정수 n을 매개변수로 입력받습니다. n의 각 자릿수를 큰것부터 작은 순으로 정렬한 새로운 정수를 리턴해주세요. 예를들어 n이 118372면 873211을 리턴하면 됩니다.

예시

입출력 예

n			return
118372		873211

내가 작성한 solution.js

function solution(n) {
    var answer = 0;
    return answer = Number(n.toString().split('').sort((a, b) => b-a).join(''));
}

이것도 숫자로 조합되어 있는 String을 큰 숫자부터 시작해서 작은 숫자로 끝나도록 재배치하는 문제라서, String을 split 하여 배열에 담고 sort()함수를 이용해 순서만 변경해주고 다시 Number로 형을 변경하였다.

0개의 댓글