Home LeetCode - Dynamic Programming
Post
Cancel

LeetCode - Dynamic Programming

Dynamic Programming

Level Easy

LeetCode0053 maximum-subarray

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
int LeetCode0053::maxContiguousSubArraySum(vector<int>& nums) {
    /**
     * Find largest sum subarray, but just return its sum.
     * Note: A subarray is a `contiguous` part of an array
     * 
     * https://leetcode-cn.com/problems/maximum-subarray/
     * 
     * Examples:
     * Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
     * Output: 6
     * Explanation: [4,-1,2,1] has the largest sum = 6.
     * 
     * Input: nums = [5,4,-1,7,8]
     * Output: 23
     * 
     * Follow up: If you have figured out the O(n) solution, try coding another solution
     * using the divide and conquer approach, which is more subtle.
     * 
     * Solutions: 
     *		let `mcsas = maxContiguousSubArraySum`
     *		
     *		transition formula: 
     *			mcsas(n) = max(mcsas(n-1), mcsas(n-1)+num[n])
     * 
     *		Keypoint: 考虑连续子序列的中断,然后重置起点的问题
     *			if sum(curSubArray) + nums[n] > num[n],则子序列保持连续,即 curSum += nums[n]
     *			else,子序列中断,curSubArray=[num[n]],即 curSum = nums[n]
     * 
     * \param nums Array numbers
     * \return maxsum of subarray
     */
    if (nums.size() == 0) { return NULL; }
    if (nums.size() == 1) { return nums[0]; }
    int maxSum = nums[0];
    int curSum = maxSum;
    for (int n = 1; n < nums.size(); ++n) {
        curSum = max(nums[n], curSum + nums[n]);
        maxSum = max(curSum, maxSum);
    }
    return maxSum;
}

LeetCode0070 climbing-stairs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
int LeetCode0070::climbStairs(int n) {
    /**
     * You are climbing a staircase. It takes n steps to reach the top.
     * Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
     *
     * https://leetcode-cn.com/problems/climbing-stairs/
     * 
     * Example:
     * 
     * Input: n = 2
     * Output: 2
     * Explanation: There are two ways to climb to the top.
     * 1. 1 step + 1 step
     * 2. 2 steps
     * 
     * Input: n = 3
     * Output: 3
     * Explanation: There are three ways to climb to the top.
     * 1. 1 step + 1 step + 1 step
     * 2. 1 step + 2 steps
     * 3. 2 steps + 1 step
     * 
     * Solutions: 
     *		transition formula: steps_n = steps_n_1 + steps_n_2
     * .
     */
    int steps_n_1 = 1, steps_n_2 = 2, steps_n = 0;
    if (n == 1) steps_n = steps_n_1;
    if (n == 2) steps_n = steps_n_2;
    for (int i = 3; i <= n; ++i) {
        steps_n = steps_n_1 + steps_n_2;
        steps_n_1 = steps_n_2;
        steps_n_2 = steps_n;
    }
    return steps_n;
}

LeetCode0118 pascals-triangle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
vector<vector<int>> LeetCode0118::generatePascalsTriangle(int numRows) {
    /** 
     * Given an integer numRows, return the first numRows of Pascal's triangle. (即杨辉三角)
     * In Pascal's triangle, each number is the sum of the two numbers directly above it
     * 
     * https://leetcode-cn.com/problems/pascals-triangle/
     * 
     * Example:
     * Input: numRows = 5
     * Output: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
     * 
     * Solutions:
     *		Boundary: n=1, array2D=[[1]]
     *		Transition Formula: 
     *			for i in 0~n-1:
     *				if i==0: array2D[n][0] = 1; 
     *				if 0<i<n-1: array2D[n][i] = array2D[n-1][i] + array2D[n-1][i-1]
     *				if i== n-1: array2D[n][n-1] = 1
     *			
     * \param numRows
     * \return All Rows
     */
    vector<vector<int>> array2D(numRows);
    for (int n = 0; n < numRows; ++n) {
        array2D[n].resize(n + 1);
        array2D[n][0] = 1;
        for (int i = 1; i < n; ++i) {
            array2D[n][i] = array2D[n - 1][i] + array2D[n - 1][i-1];
        }
        array2D[n][n] = 1;
    }
    return array2D;
 }

LeetCode0119 pascals-triangle-ii

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
vector<int> LeetCode0119::generatePascalsTriangleIIandGetLastRow(int rowIndex) {
    /**
     * Return the last row of PascalsTriangle given rowIndex
     * 
     * Same as LeetCode0118 to generate Pascals' Triangle, but this time, we do not need save all rows, 
     * only need to retain (n-1)-th row and update n-th row
     * 
     * https://leetcode-cn.com/problems/pascals-triangle-ii/
     * 
     * Solutions:
     *		Transition Formula: curRow[i] = preRow[i] + preRow[i - 1], forall i in [1,n-1]
     * 
     * \param rowIndex
     * \return 
     */
    vector<int> preRow;
    vector<int> curRow;
    for (int n = 0; n <= rowIndex; ++n) {
        for (int i = 1; i < n; ++i) {
            curRow[i] = preRow[i] + preRow[i - 1];
        }
        curRow.push_back(1);
        preRow = curRow;
    }
    return curRow;
}

LeetCode0119 pascals-triangle-ii

使用组合数学方式求解 LeetCode0119

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
vector<int> LeetCode0119::generatePascalsTriangleIIandGetLastRow2(int rowIndex) {
    /**
     * Return the last row of PascalsTriangle given rowIndex
     * 
     * Solution: Use a property of Combinatorics: 
     *			
     *		C(n,m) = n!/(n-m)!  = C(n,m-1) * (n-m+1)/m
     * 
     * \param rowIndex
     * \return The last row of PascalsTriangle given rowIndex
     */
    vector<int> row(rowIndex+1);
    row[0] = 1;
    for (int m = 1; m <= rowIndex; ++m) {
        // using 1LL to avoid overflow problem in multiplying and dividing
        row[m] = 1LL * row[m - 1] * (1LL * rowIndex - m + 1) / m;    
    }
    return row;
}

LeetCode0121 best-time-to-buy-and-sell-stock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
int LeetCode0121::maxProfit(vector<int>& prices) {
    /**
     * You are given an array prices where prices[i] is the price of a given stock on the ith day
     * You want to maximize your profit by choosing a single day to buy one stock and choosing 
     * a different day in the future to sell that stock.
     * 
     * Return the maximum profit you can achieve from this transaction. 
     * If you cannot achieve any profit, return 0.
     * 
     * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/
     * 
     * Input: prices = [7,1,5,3,6,4]
     * Output: 5
     * Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
     * Note that buying on day 2 and selling on day 1 is not allowed because you must buy before you sell.
     * 
     * Solutions: 
     *		Transition Formula: maxProfit(n) = max(maxProfit(n), maxProfit(n-1))
     *		
     *		Keypoint: 
     *			if prices[i] - min(prices[0:i-1]) > maximumProfit, 
     *			then update maximumProfit, and buyIndex
     * 
     * \param prices : an array prices 
     * \return maximum profit
     */
    int buyIndex = 0;
    int minimumPriceIndex = 0;
    int maximumProfit = 0;
    int curProfit = 0;

    for (int i = 1; i < prices.size(); ++i) {
        // record the min price of prices[0:i+1]
        if (prices[minimumPriceIndex] > prices[i] && prices[buyIndex] > prices[i]) {
            minimumPriceIndex = i;
        }
        // Update max profit if exists smaller one
        curProfit = prices[i] - prices[minimumPriceIndex];
        if (maximumProfit < curProfit) {
            maximumProfit = curProfit;
            buyIndex = minimumPriceIndex;
        }
    }
    return maximumProfit;
}

LeetCode0338 counting-bits

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
vector<int> LeetCode0338::countBits(int n) {
    /**
     * Given an integer n, return an array ans of length n + 1 such that for each i (0 <= i <= n), 
     * ans[i] is the number of 1's in the binary representation of i.
     * 
     * https://leetcode-cn.com/problems/counting-bits/
     * 
     * Input: n = 2
     * Output: [0,1,1]
     * Explanation:
     *	0 --> 0
     *	1 --> 1
     *	2 --> 10
     * 
     * Solutions: 
     *		'highestBit' Transition Formula: 
     *			if n & (n-1) == 0, then n can be a 'highestBit' number; i.e. 'highestBit' \in \{1,2,4,8,16,......\}
     *				'highestBit' number has only one bit is '1' at its highest bit.
     *				For example:
     *					bin(2)=0b10
     *					bin(16)=0b10000
     *			
     *			countBits[n] = countBits[n-highestBit] + 1
     *				For example: 
     *					bin(6)=0b101, its highestBit is bin(4)=0b100, then countBits[6] = countBits[6-4]+1 = 2
     *					bin(15)=0b1111, its highestBit is bin(8)=0b1000, then countBits[15] = countBits[15-8]+1 = 4
     *				therefor, once we have known the 'highestBit' of number 'n' , we can obtain its 1-bits count in O(1)
     * 
     *		'lowestBit' Transition Formula: using '>>' remove lowest bit, then we have: countBits[n] = countBits[n>>1] + (n&1)
     *			if 'n' is egg (lowest bit is 0), then countBits[n] = countBits[n/2] = countBits[n>>1]
     *				6>>1 = 3;    countBit[6] = countBits[3] = 2
     *				14>>1 = 7;   countBit[14] = countBits[7] = 3
     *			if 'n' is odd (lowest bit is 1), then countBits[n] = countBits[(n-1)/2] + 1 = countBits[n>>1] + 1
     *				7>>1 = 3;	countBit[7] = countBits[3] + 1 = 3
     *				15>>1 = 7;   countBit[15] = countBits[7] + 1 = 4
     *			n & 1 = 0 or 1
     *	
     *		'lowestBitof1' Transition Formula: 
     *			using the property of operator 'n&(n-1)',  we can remove the n's lowest bit of 1, 
     *			and then: conuntBits[n] = countBits[n&(n-1)]+1
     *				For example:
     *					5 & 4 = 4, i.e. 0b101 & 0b100 = 0b100, then conuntBits[5] = countBits[5&4]+1 = 2
     *					8 & 7 = 0, i.e. 0b1000 & 0b0111 = 0b0, then conuntBits[8] = countBits[8&7]+1 = 1
     * 
     * \param n
     * \return 
     */

    vector<int> counts(n + 1);
    for (int i = 1; i <= n; ++i) {
        // using 'lowestBitof1' Transition Formula
        counts[i] = counts[i & (i-1)] + 1;
    }
    return counts;
    
}

LeetCode0392 is-subsequence

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
bool LeetCode0392::isSubsequence(string s, string t) {
    /**
     * Given two strings s and t, return true if s is a subsequence of t, or false otherwise.
     * 
     * A subsequence of a string is a new string that is formed from the original string 
     * by deleting some (can be none) of the characters without disturbing the relative 
     * positions of the remaining characters. (i.e., "ace" is a subsequence of "abcde" while "aec" is not).
     * 
     * s and t consist only of lowercase English letters
     * 
     * https://leetcode-cn.com/problems/is-subsequence/
     * 
     * Example:
     * Input: s = "abc", t = "ahbgdc"
     * Output: true
     * 
     * Input: s = "axc", t = "ahbgdc"
     * Output: false
     * 
     * Follow up: Suppose there are lots of incoming s, say s1, s2, ..., sk where k >= `10^9`, 
     * and you want to check one by one to see if t has its subsequence. 
     * In this scenario, how would you change your code?
     * 
     * Solutions:
     *		Normal Solution: double pointer
     *			while i<s.size && j <t.size:
     *				if s[i] == t[j]:
     *					i++ 
     *				j++
     *			return true if i == s.size, else false
     *		
     *		(DP)Transition Formula:
     *			Let M = t.size
     *			
     *			Using a `M+1 x 26` matrix , named by 'P', P[i,j] indicates the first occurrence of 
     *			the letter 'x' in t.
     *			
     *			If some letter 'x' not in t, then we simply let P[i,'x'] = M, else P[i,'x'] should be some numnber in [0,M-1].
     *			
     *			for i in M~0: if t[i] == 'x', P[i,'x'] = i else P[i,'x'] = P[i+1,'x']
     * 
     *			Note: here 'x' represents the index of some letter in array [a,b,c,d,......,x,y,z], 
     *						for example, if currentletter is 'c' then 'x' = 2
     * 
     * \param s 
     * \param t
     * \return 
     */

    // Method1: Double Pointer
    /*int sLen = s.size(), tLen = t.size();
    int sIdx = 0, tIdx = 0;
    while (sIdx < sLen && tIdx < tLen) {
        if (s[sIdx] == t[tIdx]) sIdx++;
        tIdx++;
    }
    return sIdx == sLen;*/

    // Method2: DP solution. This method works for the scenario described in "Follow up"
    int M = t.size();
    // 1. initialize a `M+1 x 26` dimension Matrix, and fill it with 0 
    vector<vector <int>> P(M + 1, vector<int>(26, 0));
    // 2. initlialize the numbers of row P[M+1]  with "M"
    for (int j = 0; j < 26; ++j) {
        P[M][j] = M;
    }

    // 3. update matrix P respect to target string `t`
    for (int i = M - 1; i >= 0; --i) {
        for (int j = 0; j < 26; ++j) {
            if (t[i] == j + 'a') 
                P[i][j] = i;
            else 
                P[i][j] = P[i + 1][j];
        }
    }

    // 4. search if string `s` is a non-contiguous subsequence of `t` according Matrix P
    int rowIdx = 0;
    for (int n = 0; n < s.size(); ++n) {
        if (P[rowIdx][s[n] - 'a'] == M) {
            return false;
        }
        rowIdx = P[rowIdx][s[n] - 'a'] + 1;
    }
    return true;

}

LeetCode0509 fibonacci-number

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int LeetCode0509::fibonacci(int n) {
    /**
     * The Fibonacci numbers, commonly denoted F(n) form a sequence, called the Fibonacci 
     * sequence, such that each number is the sum of the two preceding ones, starting 
     * from 0 and 1. That is,
     *		
     *		F(0) = 0, F(1) = 1
     *		F(n) = F(n - 1) + F(n - 2), for n > 1.
     * 
     * https://leetcode-cn.com/problems/fibonacci-number/
     * 
     * \param n
     * \return 
     */

    // Recursion version
    /*
    if (n<=1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
    */

    // DP version: bottom up
    if (n<=1) return n;
    int fnMinus1 = 0, fnMinus2 = 1;
    int fn = fnMinus1;
    for (int i = 2; i <= n; ++i) {
        fn = fnMinus1 + fnMinus2;
        fnMinus1 = fnMinus2;
        fnMinus2 = fn;
    }
    return fn;
}

LeetCode0746 min-cost-climbing-stairs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
int LeetCode0746::minCostClimbingStairs(vector<int>& cost) {
    /**
     * You are given an integer array cost where cost[i] is the cost of ith step on a staircase.
     * Once you pay the cost, you can either climb one or two steps.
     * 
     * You can either start from the step with index 0, or the step with index 1.
     * 
     * Return the minimum cost to reach the top of the floor.
     * 
     * 2 <= cost.length 
     * 
     * https://leetcode-cn.com/problems/min-cost-climbing-stairs/
     * 
     * Example:
     * Input: cost = [10,15,20]
     * Output: 15
     * Explanation: You will start at index 1.
     * - Pay 15 and climb two steps to reach the top.
     * The total cost is 15.
     * 
     * Input: cost = [1,100,1,1,1,100,1,1,100,1]
     * Output: 6
     * Explanation: You will start at index 0.
     * - Pay 1 and climb two steps to reach index 2.
     * - Pay 1 and climb two steps to reach index 4.
     * - Pay 1 and climb two steps to reach index 6.
     * - Pay 1 and climb one step to reach index 7.
     * - Pay 1 and climb two steps to reach index 9.
     * - Pay 1 and climb one step to reach the top.
     * The total cost is 6.
     * 
     * Solutions: 
     *		Transition Formula:
     *			totalCost[n] = min(totalCost[n-1] + cost[n-1], totalCost[n-2]+cost[n-2])
     * 
     *      Note: in this problem, the finall result of n will equal cost.size.
     *		
     *		I think this is not a well defined problem.
     * 
     * \param cost
     * \return 
     */
    int n = cost.size();
    int costIMinus1 = 0, costIMinus2 = 0;
    int costI = 0;
    for (int i = 2; i <= n; ++i) {
        costI = min(costIMinus1 + cost[i - 1], costIMinus2 + cost[i - 2]);
        costIMinus2 = costIMinus1;
        costIMinus1 = costI;
    }
    return costI;
}

LeetCode1025 divisor-game

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
bool LeetCode1025::divisorGame(int n) {
    /**
     * Alice and Bob take turns playing a game, with Alice starting first.
     * 
     * Initially, there is a number n on the chalkboard.
     * On each player's turn, that player makes a move consisting of:
     *	- Choosing any x with 0 < x < n and n % x == 0.
     *	- Replacing the number n on the chalkboard with n - x.
     * 
     * Also, if a player cannot make a move, they lose the game.
     * 
     * Return true if and only if Alice wins the game, assuming both players play optimally.
     * 
     * https://leetcode-cn.com/problems/divisor-game/
     * 
     * Example:
     * Input: n = 2
     * Output: true
     * Explanation: Alice chooses 1, and Bob has no more moves.
     * 
     * Input: n = 3
     * Output: false
     * Explanation: Alice chooses 1, Bob chooses 1, and Alice has no more moves.
     * 
     * Solutions: 
     *		https://leetcode-cn.com/problems/divisor-game/solution/chu-shu-bo-yi-by-leetcode-solution/
     *	
     *		This problem is so boring. 
     *		结论是:n 为奇数的时候 Alice(先手)必败,n 为偶数的时候 Alice 必胜
     *		The optimal result is 'n%2==0' ......
     *		转换成DP问题:
     * 
     * \param n
     * \return 
     */
    return n % 2 == 0;
}

LeetCode1137 n-th-tribonacci-number

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int LeetCode1137::tribonacci(int n) {
    /**
     * The Tribonacci sequence Tn is defined as follows: 
     * T0 = 0, T1 = 1, T2 = 1, and Tn+3 = Tn + Tn+1 + Tn+2 for n >= 0.
     * Given n, return the value of Tn
     * 
     * https://leetcode-cn.com/problems/n-th-tribonacci-number/
     * 
     * Example:
     * Input: n = 4
     * Output: 4
     * Explanation:
     * T_3 = 0 + 1 + 1 = 2
     * T_4 = 1 + 1 + 2 = 4
     * 
     * Input: n = 25
     * Output: 1389537
     * 
     * 
     * \param n
     * \return 
     */
    int t0 = 0, t1 = 1, t2 = 1;
    if (n == 0) return 0;
    if (n == 1) return 1;
    if (n == 1) return 1;
    int tn = 1;
    for (int i = 3; i <= n; i++) {
        tn = t2 + t1 + t0;
        t0 = t1;
        t1 = t2;
        t2 = tn;
    }
    return tn;
}

LeetCode1646 get-maximum-in-generated-array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
int LeetCode1646::getMaximumGenerated(int n) {
    /**
     * You are given an integer n. A 0-indexed integer array nums of length n + 1 is 
     * generated in the following way:
     * - nums[0] = 0
     * - nums[1] = 1
     * - nums[2 * i] = nums[i] when 2 <= 2 * i <= n
     * - nums[2 * i + 1] = nums[i] + nums[i + 1] when 2 <= 2 * i + 1 <= n
     * Return the maximum integer in the array nums​​​.
     * 
     * https://leetcode-cn.com/problems/get-maximum-in-generated-array/
     * 
     * Example:
     * Input: n = 7
     * Output: 3
     * Explanation: According to the given rules:
     * - nums[0] = 0
     * - nums[1] = 1
     * - nums[(1 * 2) = 2] = nums[1] = 1
     * - nums[(1 * 2) + 1 = 3] = nums[1] + nums[2] = 1 + 1 = 2
     * - nums[(2 * 2) = 4] = nums[2] = 1
     * - nums[(2 * 2) + 1 = 5] = nums[2] + nums[3] = 1 + 2 = 3
     * - nums[(3 * 2) = 6] = nums[3] = 2
     * - nums[(3 * 2) + 1 = 7] = nums[3] + nums[4] = 2 + 1 = 3
     * Hence, nums = [0,1,1,2,1,3,2,3], and 
     * the maximum is max(0,1,1,2,1,3,2,3) = 3
     * 
     * Input: n = 2
     * Output: 1
     * Explanation: According to the given rules, nums = [0,1,1]. 
     * The maximum is max(0,1,1) = 1
     * 
     * Input: n = 3
     * Output: 2
     * Explanation: According to the given rules, nums = [0,1,1,2]. 
     * The maximum is max(0,1,1,2) = 2
     * 
     * 
     * 
     * \param n
     * \return 
     */
    if (n <= 1) return n;
    vector<int> nums(n + 1);
    nums[1] = 1;
    int maxNum = nums[1];
    for (int j = 2; j <= n; j++) {
        nums[j] = nums[j / 2] + nums[j / 2 + 1] * (j % 2);
        maxNum = max(maxNum, nums[j]);
    }
    return maxNum;
}

Level Medium

LeetCode0005 longest-palindromic-substring

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
string LeetCode0005::longestPalindrome(string s) {
    /**
     * Given a string s, return the longest palindromic substring in s..
     * 
     * https://leetcode-cn.com/problems/longest-palindromic-substring/
     * 
     * 1 <= s.length <= 1000
     * s consist of only digits and English letters
     * 
     * Example:
     * Input: s = "babad"
     * Output: "bab"
     * Explanation: "aba" is also a valid answer
     * 
     * Input: s = "cbbd"
     * Output: "bb"
     * 
     * Solutions:
     *		DP: 
     *		
     * 
     * \param s
     * \return 
     */
    int N = s.size();
    vector<vector<int>> P(N, vector<int>(N, 0));
    vector<int> longestPd(2);
    longestPd[1] = 1;

    for (int i = 0; i < N; ++i) {
        P[i][i] = 1;
        if (i + 1 < N && s[i] == s[i + 1]) {
            P[i][i+1] = 1;
            if (longestPd[1] < 2) {
                longestPd[0] = i;
                longestPd[1] = 2;
            }
        }
    }
    
    for (int l = 3; l <= N; ++l) {
        for (int i = 0; i < N-l+1; ++i) {
            if (s[i] == s[i + l - 1] && P[i+1][i + l - 2] == 1) {
                P[i][i + l - 1] = 1;
                if (longestPd[1] < l) {
                    longestPd[0] = i;
                    longestPd[1] = l;
                }
            }
        }
    }
    return s.substr(longestPd[0], longestPd[1]);
}
This post is licensed under CC BY 4.0 by the author.