Algorithm basic 1

2020-05-11
computer-science

칸아카데미의 알고리즘 코스를 들으며 정리해본 알고리즘 기초.
https://ko.khanacademy.org/computing/computer-science/algorithms


알고리즘


시간 복잡도 Big-O

big-o

실행 시간의 효율성을 논의할 때 최악의 경우를 따져보는 것이 가장 일반적이다. 가장 대표적인 Big-O 계산법 또한 실행 시간의 최악의 경우를 따져보는 것으로, “실행 시간은 최대한 이만큼 커지지만 더 천천히 커질 수도 있다"라는 의미의 점근적 표기법이다.


[참고]

complexity

1. 지수함수(x^n) -> 거듭제곱 수가 상수가 아니면  가파르게 복잡도 증가
2. (거듭제곱 수가 상수인) 다항함수(n^x)
3. 선형함수(n)
4. 로그함수
5. 상수

일반적으로 x가 상수이고 n이 1부터 시작한다고 하면, 아래의 순서대로 실행시간이 천천히 늘어난다. 즉, 1번이 가장 복잡도가 큰 경우이다.

ex) 입력값 n에 따라 어떠한 알고리즘이 6n^2 + 100n + 300
만큼의 복잡도를 가진다면?

-> n이 대충 30 정도만 되어도 6n^2 나머지 식들보다 커짐.
-> , n^2 의해 기하급수적으로 실행시간이 늘어남
-> 앞에 계수 6  영향을 주지 못하므로 해당 알고리즘의 복잡도는 n^2



로그함수? feat. O(log n)이 지니는 의미

로그(logarithm)는 “특정 밑(base)에 대한 거듭제곱 수"를 의미한다. 예를 들면, 밑이 2이고 진수가 8인 로그의 값은 3이다.


예시: 이진검색 (javascript)

function binarySearch(array, target) {
  let guess = 0;
  let min = 0;
  let max = array.length - 1;

  while (max >= min) {
    guess = Math.floor((max + min) / 2);

    if (array[guess] === target) {
      return guess;
    } else if (array[guess] < target) {
      min = guess + 1;
    } else {
      max = guess - 1;
    }
  }

  return -1;
}


배열에 값이 16개 있을 경우?

—> 따라서 최대 5번만 탐색하면 된다.
—> O(log n) 복잡도는 이처럼 찾는 범위를 계속 줄여주므로 효율적이라고 할 수 있다.
—> 쉽게 말하면 반으로 쪼개서 필요없는 범위는 찾지 않도록 한다는 것이며, 실무에서도 필요없는 값을 반복하는 경우가 있는데 이때 로거리즘 기법을 생각해볼 수 있겠음!



재귀는 무엇인가 ?

recursion

재귀는 자기 자신을 호출하는 방식이다?

-> 이 설명은 재귀를 ‘어떻게’ 사용하는 지를 알려주는 것에 가깝다.
-> 즉, 재귀가 무엇인지는 100% 담을 수 없는 설명인 것 같다.


[재귀란]


[재귀의 반복 조건]

  1. 재귀의 호출은 같은 문제 내에서 더 범위가 작은 값, 즉, 하위 문제에 대해 이루어져야 한다.
  2. 재귀함수 호출은 더 이상 반복되지 않는 base case에 도달해야 한다.


예시: 팩토리얼 (javascript)

const factorial = function (n) {
  if (n === 0) {
    return 1;
  }

  return n * factorial(n - 1);
};


n이 3인 경우 ?

—> 이렇게 탈출 조건을 지정하면서 동일한 작은 태스크를 반복할 수 있는 형태라면 재귀 알고리즘을 사용할 수 있다.
—> 입력값이 n개라면 n만큼 자기 자신을 호출하기 때문에 시간복잡도 O(n)



최근에 알게 된 알고리즘 기법 ?

  1. Brute force (무차별 대입 공격)
    가능한 모든 경우의 수를 반복, 조작하며 결과값을 얻는 기법
  2. Greedy (탐욕 알고리즘)
    여러 경우 중 하나를 결정해야 할 때마다 그 순간에 최적이라고 생각되는 것을 선택해 나가는 방식
  3. Sliding window

    - 윈도우의 사이즈가 3  아래 배열 탐색
    
    [a b c d e f g h]
    
    [a b c]
      [b c d]
        [c d e]
          [d e f]
            [e f g]
              [f g h]
    


  1. Two pointer

    요소를 가르킬 포인터 2개를 조작하며 결과값을 얻는 기법, 아래 문제 (javascript)처럼 처음과 끝을 가리키며 점차 범위를 좁혀갈 때 많이 활용할 수 있다!

    —> 입력값 n개에 대해 최악의 경우 n번을 반복해야 하므로 시간복잡도 O(n)

    /**
     * Container With Most Water
     * - 주어지는 물의 높이값 배열에서 가장 물을 많이 담을 수 있는 구역 찾기
     * ex) [1,8,6,2,5,4,8,3,7] -> 49
     * 계산해보면 1번째 인덱스(a)부터 8번째 인덱스(b)까지의 차이 * MIN(height[a], height[b])
     */
    const maxArea = function (height) {
      let area = 0;
      let left = 0;
      let right = height.length - 1;
    
      while (left < right) {
        area = Math.max(
          area,
          Math.min(height[left], height[right]) * (right - left)
        );
    
        if (height[left] < height[right]) left++;
        else right--;
      }
    
      return area;
    };
    


  1. Eratosthenes sieve (에라토스테네스의 체)

    N까지의 소수를 구할 때 최적의 방법. N까지 담겨있는 일종의 체에서 2의 배수, 3의 배수… i의 배수를 걸러내면서 루프를 돌면 마지막에는 소수만 남게 된다.

    /*
     * 소수 (prime number)
     * - 원래 n까지 돌면서 n보다 작은 수까지만 n과 나누어 나머지가 0이 아닌 수를 소수로 체크했으나, 효율성이 낮음
     * - n까지의 소수 구하기에 최적화된 방법은 에라토스테네스의 체 알고리즘임
     * - n까지의 수를 담은 배열이 있고, 그 배열에서 2의 배수, 3의 배수, ... i의 배수를 계속 지우면 소수만 남게 됨
     */
    function solution(n) {
      const dp = Array(n + 1);
    
      // O(n)
      for (let i = 2; i <= n; i++) dp[i] = i;
    
      // O(log n)
      for (let i = 2; i <= n; i++) {
        if (dp[i] === 0) continue;
    
        // i를 포함한 i의 배수를 구해 지움
        for (let k = i * 2; k <= n; k += i) {
          dp[k] = 0;
        }
      }
    
      return dp.filter((v) => v > 0).length;
    }
    

백준 알고리즘을, 특히 파이썬으로 풀면서 참고할 것들 정리

2024-01-20
computer-science

After reading <code>

2020-11-18
review computer-science

After reading <concepts of programming languages>

2020-06-28
review computer-science
comments powered by Disqus