Dynamic Programming (DP) was developed by Richard Bellman in the 1950s and has found applications in numerous fields, from aerospace engineering to economics.

 

DP is an algorithm technique that is closely related to the divide and conquer approach. However, while the divide and conquer approach is essentially recursive, and so "top down", dynamic programming works "bottom up".

 

This method is an optimisation approach that transforms a complex problem into a sequence of simpler problems. It creates an array of related but simpler sub-problems, and then, it computes the solution to the big complicated problem by using the solution to the easier sub-problems which are stored in the array. In this way, the efficiency of the CPU can be enhanced.

 

DP solutions have a polynomial complexity which assures a much faster running time than other techniques like backtracking, brute-force etc. For example, the following simple recursive solution (top down) for Fibonacci Numbers gets exponential time complexity.

int fib (int n) {
    if (n <= 1)
    	return n;
    return fib(n - 1) + fib(n - 2);
}

The time complexity reduces to linear in the below-optimised code (bottom up).

std::vector<int> f{0, 1};
for (int i = 2; i <= n; ++i) {
	f.emplace_back(f[i - 1] + f[i - 2]);
}
return f[n];

DP works by storing the result of sub-problems so that when their solutions are required, they are at hand and we do not need to recalculate them. The technique of storing the results of already solved sub-problems is called memoisation. By saving the values in the array, we save time for computations of sub-problems we have already come across.

'Algorithms' 카테고리의 다른 글

Manacher's Algorithm  (0) 2021.09.12
Window Sliding Technique  (0) 2021.09.11
Hopcroft-Karp algorithm (호프크로프트-카프)  (0) 2021.09.05
Breadth-first, Depth-first searches (BFS/DFS)  (0) 2021.09.03
Recursion vs. Iteration for Fibonacci  (0) 2021.08.25

A DNA sequence can be represented as a string consisting of the letters A, C, G and T, which correspond to the types of successive nucleotides in the sequence. Each nucleotide has an impact factor, which is an integer. Nucleotides of types A, C, G and T have impact factors of 1, 2, 3 and 4, respectively. You are going to answer several queries of the form: What is the minimal impact factor of nucleotides contained in a particular part of the given DNA sequence?

The DNA sequence is given as a non-empty string S = S[0]S[1]...S[N-1] consisting of N characters. There are M queries, which are given in non-empty arrays P and Q, each consisting of M integers. The K-th query (0 ≤ K < M) requires you to find the minimal impact factor of nucleotides contained in the DNA sequence between positions P[K] and Q[K] (inclusive).

For example, consider string S = CAGCCTA and arrays P, Q such that:

P[0] = 2 Q[0] = 4 P[1] = 5 Q[1] = 5 P[2] = 0 Q[2] = 6

The answers to these M = 3 queries are as follows:

  • The part of the DNA between positions 2 and 4 contains nucleotides G and C (twice), whose impact factors are 3 and 2 respectively, so the answer is 2.
  • The part between positions 5 and 5 contains a single nucleotide T, whose impact factor is 4, so the answer is 4.
  • The part between positions 0 and 6 (the whole string) contains all nucleotides, in particular nucleotide A whose impact factor is 1, so the answer is 1.

Write a function:

vector<int> solution(string &S, vector<int> &P, vector<int> &Q);

that, given a non-empty string S consisting of N characters and two non-empty arrays P and Q consisting of M integers, returns an array consisting of M integers specifying the consecutive answers to all queries.

Result array should be returned as a vector of integers.

For example, given the string S = CAGCCTA and arrays P, Q such that:

P[0] = 2 Q[0] = 4 P[1] = 5 Q[1] = 5 P[2] = 0 Q[2] = 6

the function should return the values [2, 4, 1], as explained above.

Write an efficient algorithm for the following assumptions:

  • N is an integer within the range [1..100,000];
  • M is an integer within the range [1..50,000];
  • each element of arrays P, Q is an integer within the range [0..N − 1];
  • P[K] ≤ Q[K], where 0 ≤ K < M;
  • string S consists only of upper-case English letters A, C, G, T.
vector<int> solution(string &S, vector<int> &P, vector<int> &Q) {
    vector<int> ans;
    int A[S.length()+1];
    int C[S.length()+1];
    int G[S.length()+1];
    int T[S.length()+1];
    A[0] = 0;
    C[0] = 0;
    G[0] = 0;
    T[0] = 0;
    for (int i = 0; i < S.length(); i++)
    {
        A[i+1] = A[i];
        C[i+1] = C[i];
        G[i+1] = G[i];
        T[i+1] = T[i];
        switch (S[i])
        {
            case 'A':
                A[i+1] = A[i] + 1;
                break;
            case 'C':
                C[i+1] = C[i] + 1;
                break;
            case 'G':
                G[i+1] = G[i] + 1;
                break;
            case 'T':
                T[i+1] = T[i] + 1;
                break;
        }
    }
    for (int i = 0; i < P.size(); i++)
    {
        if (A[P[i]] < A[Q[i]+1])
        {
            ans.push_back(1);
            continue;
        }
        if (C[P[i]] < C[Q[i]+1])
        {
            ans.push_back(2);
            continue;
        }
        if (G[P[i]] < G[Q[i]+1])
        {
            ans.push_back(3);
            continue;
        }
        if (T[P[i]] < T[Q[i]+1])
        {
            ans.push_back(4);
            continue;
        }
    }
    return ans;
}

Detected time complexity: O(N + M)

'Challenge' 카테고리의 다른 글

[LeetCode] Remove Nth Node From End of List  (0) 2021.10.07
[LeetCode] 4Sum  (0) 2021.10.07
[LeetCode] Letter Combinations of a Phone Number  (0) 2021.10.06
[LeetCode] 3Sum Closest  (0) 2021.10.06
[LeetCode] 3Sum  (0) 2021.10.06

Given the head of a linked list, remove the nth node from the end of the list and return its head.

 

Example 1:

Input: head = [1,2,3,4,5], n = 2 Output: [1,2,3,5]

Example 2:

Input: head = [1], n = 1 Output: []

Example 3:

Input: head = [1,2], n = 1 Output: [1]

 

Constraints:

  • The number of nodes in the list is sz.
  • 1 <= sz <= 30
  • 0 <= Node.val <= 100
  • 1 <= n <= sz
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        if (!head->next) return NULL;
        ListNode *ans = head, *cur = head;
        for (int i = 0; i < n; i++) cur = cur->next;
        if (!cur) return head->next;
        while (cur->next)
        {
            cur = cur->next;
            ans = ans->next;
        }
        ans->next = ans->next->next;
        return head;
    }
};

'Challenge' 카테고리의 다른 글

[Codility] GenomicRangeQuery  (0) 2021.10.09
[LeetCode] 4Sum  (0) 2021.10.07
[LeetCode] Letter Combinations of a Phone Number  (0) 2021.10.06
[LeetCode] 3Sum Closest  (0) 2021.10.06
[LeetCode] 3Sum  (0) 2021.10.06

+ Recent posts