본문 바로가기

IT 공부/알고리즘 (컴퓨팅 사고력 연습)12

[피드백] - 일상 언어를 제대로 이해하자. (문제 해석 실패 사례) 컴퓨터로 문제를 해결할 때, 코딩테스트처럼 미리 전산학/컴퓨터공학적 개념으로 잘 정리된 문제라고 해도 어느 정도는 일상 언어를 통해 문제 사항이 기술된다. 여기서 프로그래머는 요구 사항을 정확하게 해석해야 한다. 이를 위해 커뮤니케이션이 필요하다. 아래는 내 실수다. 문제는 다음과 같다. N개의 사탕을 3명의 어린이에게 나눠주려고 한다. 최대한 공평하게 나누려고 한다. 공평함의 기준은 받는 사탕의 총 무게를 기준으로 가장 무거운 어린이의 사탕 무게와 가장 가벼운 어린이의 사탕 무게의 차이다. 사탕의 무게는 20이하의 정수로 주어진다. 가장 공평한 분배일 때의 무게 차이를 구하는 알고리즘은? 여기서 나는 나름 꽤 만족스런 해법을 고안했으나 결과적으로 완전히 틀린 대답이 되고 말았는데, 그 이유는 문제의 요.. 2024. 3. 25.
주어진 합을 가지는 특정 구간 구하기 문제. 수열과 어떤 값 하나가 주어진다. 구간의 합이 특정 값인 구간을 구하라. 이 문제를 풀기 위한 아이디어로 다음과 같이 생각했다. 1. 시간복잡도 시간복잡도는 적어도 O(N)이다. 절대로 이것보다 낮을 수는 없다. 구간의 "합"을 알아야 하므로 최악의 경우 수열의 전체 구간이 답이 될 수도 있기 때문이다. 2. 나에게 주어진 정보 보통 알고리즘의 Big-O가 N^2이나 N^3이 되는 이유는 불필요한 계산을 하기 때문이다. 불필요한 계산은 문제에서 주어진 정보나, 본인이 계산을 진행해가며 얻은 값들을 정보로 활용하지 않을 때 발생한다. 그래서 나에게 주어진 정보는 아래와 같았다. 문제에서 주어진 정보 = 구간의 값. 계산을 하며 얻을 수 있는 정보 = 0번째 배열부터 시작해 p 까지의 누적합. 3. .. 2024. 3. 20.
문제를 정확히 정의할 줄 아는 능력... 1. 디스크 파일 정렬 문제 존 벤틀리의 의 첫 칼럼에서는 아래와 같은 사례가 있다. 그 프로그래머의 질문은 간단했다. "디스크 파일을 어떻게 정렬하지?" 내가 처음에 어떤 실수를 했는지 말하기 전에, 여러분에게 내가 했던 대답보다 더 잘 할 수 있는 기회를 주겠다. 여러분이라면 어떻게 대답했을까? 처음에 저자는 아무 생각없이 "merge sort를 써" 라고 대답했다. 그러나 이내 자신이 엉뚱한 대답을 했다는 것을 깨달았다. 프로그래머가 처한 문제 상황은 정확히 다음과 같았기 때문이다. 이 기능은 큰 시스템의 일부이기 때문에 메모리를 많이 사용할 수 없다. 기껏해야 1MB 정도다. 파일은 최대 10,000,000(1천만)개의 레코드를 가진다. 각 레코드는 7자리 양의 정수이며, 모든 정수는 서로 중복되.. 2023. 11. 29.
주식 가격 문제 - 거꾸로 생각하기는 정말 중요하다. 1. 주식 가격 문제 프로그래머스 코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요. programmers.co.kr 문제를 간략하게 요약하면 아래와 같다. 초 단위로 기록된 주식 가격이 담긴 배열이 매개변수로 주어진다. 각 초를 기준으로 가격이 떨어지지 않은 기간은 몇 초 인지 return하라. prices = [1, 2, 3, 2, 3] 이면 return = [4, 3, 1, 1, 0] 해석하자면, 첫 번째 기간의 가격은 1이다. 1 입장에서는 4기간 동안은 가격이 떨어진 적이 없다. 따라서 4다. 두 번째 기간의 가격은 2다. 역시나 떨어진 적이 없으므로 3기간이다. 세 번째 기간의 가격은 3인데,.. 2023. 11. 10.
짝 찾기 문제와 스택의 본질 1. 짝 찾기 문제 문제는 아래와 같다. ( 또는 ) 로만 구성된 문자열 s가 주어진다. 문자열 s가 올바른 괄호이면 true를 return하고, 올바르지 않다면 false를 return 하는 solution 함수를 작성하라. 괄호가 바르게 짝 지어졌다는 것은 ( 문자로 열렸다면 반드시 ) 문자로 닫혀야 한다는 뜻이다. 예를 들어, "()()" 는 올바른 문자열이다. "(())()" 도 올바른 문자열이다. 문제의 해답은 스택을 사용하면 아주 쉽게 풀린다. 아이디어도 매우 간단하다. 문자열을 순서대로 접근해 스택에 넣는다. 이때 닫는 괄호 )가 나오면 스택에서 데이터를 하나 pop 하자. 해당 문자 ( 는 이제 처리되어 소거된다. 이런 논리를 계속 반복하다보면 문자열 접근이 완료되면 스택도 전부 비어있게 .. 2023. 11. 10.
오늘의 피드백 - 거꾸로 생각할 때 주의할 점. 1. N개의 수열에서 구간의 합이 최대인 구간 찾기 문제는 아래와 같다. N개의 정수가 담긴 수열이 주어진다. 이때 특정 구간의 합이 최대가 되는 구간을 찾는 효율적인 방법은? 문제는 워낙 간단하다. 그래서 무식하게 풀 수 있다. 존재할 수 있는 모든 구간 (p, q) 범위를 for 문을 통해 일일이 접근한다. 해당 구간의 합을 구해서 최대인지 확인한다. 그러나 이러한 방식은 시간복잡도가 사실상 쓸모 없는 수준이다. O(N^3)이다. 무려 세제곱이다. for 문을 통해 모든 p, q 구간을 접근해야 하므로 N 제곱의 처리가 소요되고, 또 더하기 연산을 위해서 또 O(N)이 필요하다. 즉, 복잡도는 세제곱이다. 개선해봤자 O(N^2)이 될 뿐이다. 특정 p 값에서 시작해서 q를 하나씩 늘려나가면 이전에 사.. 2023. 11. 7.
스택 자료구조의 본질과 진정한 의미 1. 스택의 실생활 예시?? 스택(Stack)이란 선형 자료구조 중 하나로, 위 그림과 같이 데이터를 적재(push)하고, 나중에 다시 데이터를 가져올 때는 최근에 적재한 데이터를 가져오는(pop) 자료 구조를 말한다. A, B, C 순서대로 데이터를 넣으면 반드시 C, B, A 순서대로 데이터를 처리한다. 이를 선입후출(Last In, First Out, LIFO)라 한다. 흔히 스택을 처음 배울 때, 아래와 같은 실생활 비유를 들어 스택을 받아들인다. 나도 그랬다. 스택과 비슷한 구조를 실생활에서 찾는 것은 그리 어렵지 않다. stack이라는 말 그대로, 무언가를 쌓아올리는 것이기 때문이다. 처음 스택을 배울 때는 이런 이미지를 그려보는 것이 도움이 된다. 그러나 조금만 더 깊게 들어가면 위 예시들은.. 2023. 11. 6.
수열에서 중간값 찾기 문제와 분할/정복 알고리즘의 정수 1. 중간값 찾기 문제 임의의 N개의 원소를 가진 수열이 주어졌을 때, 그 중간값을 찾는 문제다. 여기서 중간값이란 그 값을 기준으로 작은 모든 원소들과 그 값보다 큰 모든 원소들을 이등분하는 값을 말한다. 간단하게 생각하면 정말 정의 그대로, 그냥 주어진 배열을 정렬하고 중간에 있는 값을 선택하면 될 것 같다. 물론 그렇게 해도 풀리며, O(N logN) 정렬 알고리즘을 선택해 사용하면 될 것이다. 그러나 이렇게 푸는 것은 매우 아쉽다. 컴퓨팅 사고력에서 중요한 능력 중 하나는 쓸데없는 계산을 줄이는 것이라고 배웠다. 지금 문제는 중간값을 찾으면 되지, 굳이 정렬까지 할 필요는 없다. 위치만 알면 되기 때문이다. 나는 이 문제를 N/2 크기의 힙(Heap) 자료구조를 이용하는 식으로 생각했다. Min .. 2023. 11. 2.
분할 정복의 진정한 핵심은 정보 구축하기! (feat. 합병 정렬) 1. 합병 정렬(Merge Sort)이란? 정렬이란 임의의 데이터 배열을 일정한 규칙에 따라 배열하는 알고리즘을 말하며, 그 종류는 여러 가지가 있다. 기초 알고리즘 수업 시간에 다루는 정렬 알고리즘에는 "버블 정렬", "선택 정렬", "삽입 정렬", "합병 정렬", "퀵 정렬", ... 등이 있다. 이 중에서 버블과 선택, 그리고 삽입 정렬은 인간의 직관적인 정렬 방식을 그대로 프로그래밍 언어로 풀이한 것으로서, 사실상 컴퓨터 과학에서 다룰 가치가 전혀 없다. 데이터 개수(N)가 증가할수록 N의 제곱으로 처리량이 증가하기 때문이다. (여담이지만 직관적인 방식으로 알고리즘을 풀면 보통 쓸만한 알고리즘이 나오지 않는 것 같다.) 그러나 합병 정렬부터는 실질적으로 사용할 수 있다. 시간복잡도가 O(N log.. 2023. 10. 31.