[프로그래머스 알고리즘] 두 정수 사이의 합

Heejun Kwon·2021년 5월 19일
0

알고리즘 풀이

목록 보기
2/11
post-thumbnail

프로그래머스 연습문제
프로그래머스 - 두 정수 사이의 합


🔎 문제

두 정수 a, b가 주어졌을 때 a와 b 사이에 속한 모든 정수의 합을 리턴하는 함수, solution을 완성하세요.

예를 들어 a = 3, b = 5인 경우, 3 + 4 + 5 = 12이므로 12를 리턴합니다.

🚫 제한조건

a와 b가 같은 경우는 둘 중 아무 수나 리턴하세요.

a와 b는 -10,000,000 이상 10,000,000 이하인 정수입니다.

a와 b의 대소관계는 정해져있지 않습니다.

💻 입출력 예


📄🤔 코드 및 풀이과정

🔹 1번

public long solution(int a, int b) {
       
    long answer = 0;
        
    int maxV = Math.max(a, b);
    int minV = Math.min(a, b);
        
    for(int i = minV; i <= maxV; i++){
        answer += i;
    }
        
    return answer;
}

🔸 1번 풀이

처음에는 단순하게 둘 중 작은 값과 큰 값을 구하고,
for 반복문을 통해서 사이의 값들을 더하면 될 것이라는 생각에
1번과 같이 문제를 풀었다. 그리고 통과했다.

하지만 제한 조건 2번인
"a와 b는 -10,000,000 이상 10,000,000 이하인 정수입니다." 를 생각해봤을 때,
두 수 간에 범위가 매우 큰 경우 반복문이 최대 수천만번까지도 돌아가면서
매우 비효율적이고 느린 처리를 하겠구나 라는 생각이 들었다.

이러한 생각을 뒷받침하듯
테스트 결과에 나오는 통과 시간이나 테스트 점수도 좋지 않았다.

🔹 2번

public long solution(int a, int b) {
       
    long answer = ((a + b) * (Math.abs(a - b) + 1)) / 2;
        
    return answer;
}

🔸 2번 풀이

어떻게 수정할지 고민하던 중 한가지 경험을 떠올렸다.

학교에서 1부터 100까지의 합을 구할 경우 하나하나 더하는 것이 아닌
첫 수 1과 마지막 수 100을 더한 뒤,
범위에 있는 수의 갯수만큼 곱하고 2로 나눠
쉽게 5050이라는 결과값을 구했던 경험을 말이다.

위의 방법을 가우스의 덧셈이라 하며 이번 문제에 응용했는데,
이번 경우엔 음수까지 범위에 해당하므로 공식이 약간 달라진다.

(a + b) * (|(a - b)| + 1) / 2

첫 수와 마지막 수를 더한 값에
두 수의 차의 절대값 + 1 로 구한 범위 내 숫자 갯수를 곱해준다.
그리고 2로 나누어주면 된다.

위의 공식을 적용해 문제를 풀었더니 훨씬 짧은 코드로
더 효율적인 로직을 짤 수 있었다.

🔹 3번

//2번에서 캐스트연산자 (long) 추가
public long solution(int a, int b) {
       
    long answer = (((long)a + b) * (Math.abs(a - b) + 1)) / 2;
        
    return answer;
}

🔸 3번 풀이

하지만 2번 코딩은 일부 테스트만 통과하고, 몇몇 테스트를 통과하지 못해 잘못된 코딩이라는 결과를 얻었다.

애초에 로직을 잘못 짠건가? 어딘가에 간과한 부분이 있는건가? 하고
머리를 쥐어짜내며 생각해 봐도 로직에 문제가 있는 것 같지는 않았다.

그렇게 고민을 거듭하며 원인을 찾기 위해 검색을 하던 도중, 오버플로우라는 글자가 눈에 들어오면서 오버플로우에 대해 배웠던 기억이 났다.

매개변수로 받아오는 값이 int형이기 때문에
매개변수를 그대로 연산에 사용할 경우
곱셈 시 곱셈 결과가 int형의 최대 범위인 21억을 넘어가
오버플로우가 발생해 전혀 다른 값의 결과가 나옴으로 문제가 발생했던 것이다.

결과값을 저장하는 변수가 long형이라 오버플로우 생각을 안하고 있었는데
연산 과정에서 이미 오버플로우가 발생해 잘못된 값이 저장된 것이다.

해결방법은
매개변수 a와 b를 각각 long형 변수로 받아 이로 연산을 하는 방법,
매개변수를 애초에 long형으로 받는 방법,
연산 과정에서 캐스트 연산자로 값 하나를 long형으로 하여 연산 과정 전체가
long형 결과값이 나오는 방법 등이 존재한다.

첫번째 방법은 변수 두개를 추가로 선언해야 하고
두번째 방법은 처음 주어진 메서드 틀을 변경해야 해서
캐스트 연산자 (long) 하나만 추가해 주면 되는 세번째 방법을 사용했고
무사히 테스트 통과라는 결과를 얻었다.

😳❕ 소감 & 느낀점

처음엔 무척 쉽다고 생각한 문제였는데 생각보다 많은걸 느낀 것 같다.

단순히 문제를 해결하는 것만이 아니라
효율적으로 문제를 푸는 것의 중요함을 느꼈다.

이전에 공부를 할 땐, 항상 결과가 잘 나오면 그만이라는 생각에
원하는 결과만 나오면 효율을 크게 신경쓰지 않았었다.

하지만 1번 코드를 작성할 때 처럼 효율을 따지지 않고 로직을 짠다면
이것이 쌓이고 쌓여 매우 느린 프로그램을 만드는구나 하며 반성하게 되었다.

앞으로는 쉬운 기능, 문제라 하더라도 과연 이것이 가장 효율적일까?
라는 의문을 항상 가지도록 해야겠다.

또한 이론으로만 배웠던 오버플로우를 고려하는 것이 얼마나 중요한지 느꼈다.

오버플로우는 발생을 해도 에러메시지가 뜨지 않고
프로그램이 작동을 하니 더 골치아프다는 말을 단번에 이해할 수 있었다.

이론으로만 배울 때는 그렇게 중요성을 느끼지 못했는데
이렇게 몸소 경험하게 되니 애초부터 연산할 때에
오버플로우 가능성을 꼼꼼히 따지면 이런 고생을 하지 않겠구나 느꼈다.

0개의 댓글