LeetCode-dp exercises derived from the punch card problem

Write in front

Today's LC punch card is easy, but it uses dp to solve it. I think it is very helpful for the practice of dp thinking. In addition, many big guys have listed many similar questions in the solution, so I will write it together. And sort it out. (Fighting family robbery series + ugly number series)

Interview Question 17.16. Masseur

A well-known masseuse will receive a steady flow of appointment requests, and each appointment can be selected or not. There is a break between each appointment service, so she cannot accept adjacent appointments. Given an appointment request sequence, find the optimal set of appointments for the masseur (the longest total appointment time) and return the total number of minutes.

Example 1:

Input: [1,2,3,1]

Output: 4

Explanation: Select appointment No. 1 and appointment No. 3, total duration = 1 + 3 = 4.

Solution: The status of the previous bit is only selected and unselected, and then the current position can be found according to the status of the previous bit to find the maximum value of the current selected and unselected.

Recursive equation: dp [i] = max (dp [i-1], dp [i-2] + nums [i])

This problem does not need to use dp array, two dp variables will do.

Code:

class Solution {
public:
    int massage(vector<int>& nums) {
        if(nums.empty()) return 0;
        int dp0 = 0;
        int dp1 = nums[0];
        int i=1;
        while(i<nums.size()){
            int t0 = max(dp0,dp1);
            int t1 = max(dp0+nums[i],dp1);
            dp0 = t0;
            dp1 = t1;
            ++i;
        }
        return max(dp0,dp1);
    }
};

198. Fighting at home

You are a professional thief and plan to steal houses along the street. There is a certain amount of cash hidden in each room. The only limiting factor that affects your theft is that the neighboring houses are equipped with an interconnected anti-theft system. If two neighboring houses are hacked into the same night, the system will automatically call the police .

Given a non-negative integer array representing the amount of money stored in each house, calculate the maximum amount you can steal without touching the alarm device.

The prototype of the previous question is actually this classic thief problem, which is exactly the same, so I won't write it here.

213. Family Fight II

You are a professional thief and plan to steal houses along the street, each room contains a certain amount of cash. All houses in this place are in a circle, which means that the first house and the last house are next to each other. At the same time, the neighboring houses are equipped with an interconnected anti-theft system. If two neighboring houses are broken into by a thief on the same night, the system will automatically call the police.

Given a non-negative integer array representing the amount of money stored in each house, calculate the maximum amount you can steal without touching the alarm device.

Solution: In fact, it becomes a ring, and the head and tail need to be specially judged, so it is divided into the larger value of the two answers: no head selection and no tail selection.

Code:

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.empty()) return 0;
        if(nums.size()==1) return nums[0];
        int dp0 = 0;
        int dp1 = nums[0];
        int i=1;
        while(i<nums.size()-1){
            int t0 = max(dp0,dp1);
            int t1 = max(dp0+nums[i],dp1);
            dp0 = t0;
            dp1 = t1;
            ++i;
        }
        int res1 = max(dp0,dp1);
        dp0 = 0;
        dp1 = nums[1];
        i=2;
        while(i<nums.size()){
            int t0 = max(dp0,dp1);
            int t1 = max(dp0+nums[i],dp1);
            dp0 = t0;
            dp1 = t1;
            ++i;
        }
        int res2 = max(dp0,dp1);
        return max(res1,res2);
    }
};

337. Family Fight III

After the last robbery of a street and a circle of houses, the thief found a new area that could be stolen. There is only one entrance in this area, which we call "root". In addition to the "root", each house has one and only one "parent" house connected to it. After some reconnaissance, the clever thief realized that "the arrangement of all houses in this place is similar to a binary tree." If two directly connected houses are robbed on the same night, the house will automatically call the police.

Calculate the maximum amount a thief can steal a night without triggering the alarm.

Solution: The idea is the same, but because it has become a binary tree storage, it has become a tree-shaped dp.

For a subtree, there are two cases:

  1. Contains the current root node
  2. Does not contain the current root node

Case 1: Including the root node

Since the root node is included, the left and right son nodes cannot be selected. The maximum value in this case is:
current node + left son case 2 + right second child case 2

Case 2: The root node is not included

In this case, you can choose the left and right son nodes, so there are four possibilities:

  1. Left son case 1 + Right son case 1
  2. Left Son Case 1 + Right Son Case 2
  3. Left son case 2 + Right son case 1
  4. The left son case 2 + the right son case 2 is a
    combination of max (left son case 1, left son case 2) + max (right son case 1, right son case 2).

Combining these two cases, dfs traverses the binary tree.

Source: https://leetcode-cn.com/problems/house-robber-iii/solution/cdong-tai-gui-hua-si-xiang-shi-xian-xiang-xi-shuo-/

Code:

/**
* Definition for a binary tree node.
* struct TreeNode {
*     int val;
*     TreeNode *left;
*     TreeNode *right;
*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
    pair<int, int> dfs(TreeNode *root) {
        if (root == nullptr) {
            return { 0, 0 };
        }
        auto left_pair = dfs(root->left);
        auto right_pair = dfs(root->right);
        return {root->val + left_pair.second + right_pair.second, 
                max(left_pair.first, left_pair.second) + max(right_pair.first, right_pair.second)};
    }
    int rob(TreeNode* root) {
        auto p = dfs(root);
        return max(p.first, p.second);
    }
};

After finishing the series of fighting and looting, it is better to practice similar simple dp questions together.

1262. The largest sum divisible by three

Give you an integer array nums, please find and return the maximum sum of elements that can be divided by three.

Example 1:

Input: nums = [3,6,5,1,8]

Output: 18

Explanation: Select the numbers 3, 6, 1 and 8, and their sum is 18 (the largest sum divisible by 3).

Solution:

Let dp [i] represent the cumulative number of selected numbers and the modulo 3 = i number and

assume nums [i]% 3 = 1. Then, add the previously selected number and the modulo 3 = 2 number. Modulus 3 is 0, expressed as dp [0] = max (dp [0], nums [i] + dp [2])

and so on, as long as the dp array is constantly updated, pay attention to it, and save it when updating The value of a state to avoid repeated effects during subsequent updates.

Code:

class Solution {
public:
    int maxSumDivThree(vector<int>& nums) {
        vector<int> dp={0,0,0};
        for(int i=0; i<nums.size(); i++){
            int mod = nums[i] % 3;

            int a = dp[(3+0-mod)%3];
            int b = dp[(3+1-mod)%3];
            int c = dp[(3+2-mod)%3];

            if( a || mod==0) dp[0] = max(dp[0],a+nums[i]);
            if( b || mod==1) dp[1] = max(dp[1],b+nums[i]);
            if( c || mod==2) dp[2] = max(dp[2],c+nums[i]);
        }
        return dp[0];
    }
};

801. The minimum number of exchanges that increase the sequence

We have two integer arrays A and B of equal length and not empty.

We can exchange the elements of A [i] and B [i]. Note that these two elements should be in the same position in their respective sequences.

After exchanging some elements, both arrays A and B should be strictly increasing (the conditions for strictly increasing arrays are only A [0] <A [1] <A [2] <… <A [A.length-1] ).

Given arrays A and B, please return the minimum number of exchanges that keeps both arrays strictly increasing. It is assumed that the given input is always valid.

Example:

Input: A = [1,3,5,4], B = [1,2,3,7]

Output: 1

Explanation: After

swapping A [3] and B [3], the two arrays are as follows:

A = [1, 3, 5, 7], B = [1, 2, 3, 4]

Both arrays are strictly increasing.

note:

  1. The lengths of the two arrays A and B are always equal, and the length range is [1, 1000].
  2. A [i], B [i] are all integers in the range [0, 2000].

Solution:

For each column number, there are two states, change or not change, so we define two dp variables to store the state.

Initialization: If there is only one column: then dp = [0, 1]

dp [0] = 0, no exchange, the total exchange number is 0.

dp [1] = 1, exchange, the total exchange number is 1, and also meet The final requirement is an incremental sequence, because the array has only one element.


If there are two columns, suppose a1 = A [i-1], b1 = B [i-1] and a2 = A [i], b2 = B [i], i = 1
there are 4 cases

(1) a1 <a2 and b1 <b2

indicate that the current column is not exchanged with the previous column, because the condition is satisfied.

(2) a1 <b2 and b1 <a2

indicate that the current column can be exchanged relative to the previous column, because the conditions can be met after the exchange.

(3) not a1 <a2 or not b1 <b2

is (1) negated. The current column must be exchanged relative to the previous column. The exchange here is relative. If the previous column has already been exchanged, the current column may not move.

(4) not a1 <b2 or not b1 <a2

is (2) negated, the current column must not be changed relative to the previous column.


For (3)

new_dp [0] = dp [1], if the current column does not move, then the previous column must be changed.
new_dp [1] = dp [0] + 1, to change the current column, the previous column must not be moved. In short, for case (3), the opposite of the previous column is correct.

For (4)

new_dp [0] = dp [0], if the current column does not move, then the previous column must not move
new_dp [1] = dp [1] + 1, to change the current column, the previous column must also be changed. In short, for case (4), the same operation as the previous column is correct.

But (3) (4) does not cover all the cases. For (1) and (2), it can be changed or not. According to the principle of greed, it is not changed if it can.

new_dp [0] = min (dp [0], dp [1]), no matter you changed it before, I took the smaller number, and then I do n’t change it.

new_dp [1] = min (dp [0], dp [1]) + 1, no matter you changed it before, I took the smaller number and then changed it, because dp [1] corresponds to the current column The exchange situation, so no matter what, this value must correspond to the current column swap operation.

Code:

class Solution {
public:
    int minSwap(vector<int>& a,vector<int>& b) {
        vector<int> dp = {0,1};
        for(int i=1; i<a.size(); i++){
            int a1 = a[i-1];
            int a2 = a[i];
            int b1 = b[i-1];
            int b2 = b[i];

            if(a1>=a2 || b1>=b2){
                int t = dp[0];
                dp[0] = dp[1];
                dp[1] = t + 1;
            }
            else if(a1>=b2 || b1>=a2){
                ++dp[1];
            }
            else{
                int m = min(dp[0],dp[1]);
                dp[0] = m;
                dp[1] = m+1;
            }
        }
        return min(dp[0], dp[1]);
    }
};

After practicing the above problems, we will make another classic series: ugly numbers

263. Ugly number

Write a program to judge whether the given number is ugly.

An ugly number is a positive integer that contains only prime factors 2, 3, and 5.

Solution: The first one has nothing to say, ordinary violence.

Code:

class Solution {
public:
    bool isUgly(int num) {
        if(num==0) return false;
        while(num%2==0) num /= 2;
        while(num%3==0) num /= 3;
        while(num%5==0) num /= 5;
        return num==1;
    }
};

264. Ugly Number II

Write a program to find the nth ugly number.

An ugly number is a positive integer that contains only prime factors 2, 3, and 5.

Example:

Input: n = 10

Output: 12

Explanation: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 are the first 10 ugly numbers.

Solution: Use three pointers, representing 2, 3, 5, respectively, and then record the number corresponding to the position of the pointer multiplied by the minimum value of the corresponding multiple, the selected pointer +1, until the nth is counted.

Code:

class Solution {
public:
    int nthUglyNumber(int k) {
        if(k==1) return 1;
        int a(0),b(0),c(0);//记录2,3,5对应的位置
        vector<int> dp;
        dp.push_back(1);
        int s = 1;
        while(dp.size()<k){
            int next = min(2*dp[a],min(3*dp[b],5*dp[c]));
            if(next==2*dp[a]) a++;//选中的指针要+1
            if(next==3*dp[b]) b++;
            if(next==5*dp[c]) c++;
            dp.push_back(next);
        }
        return dp.back();
    }
};

Interview Question 17.09. Kth number

Some numbers have only prime factors of 3, 5, 7, please design an algorithm to find the kth number. Note that it is not necessary to have these prime factors, but must not contain other prime factors. For example, the first few numbers should be 1, 3, 5, 7, 9, 15, 21 in order.

It is exactly the same as the previous question, except that the changes of the three factors are as long as they are relatively prime, the previous solution is feasible.

313. Super ugly number

Write a program to find the nth super ugly number.

Super ugly numbers mean that all their prime factors are positive integers in the primes list primes of length k.

Example:

Input: n = 12, primes = [2,7,13,19]

Output: 32

Explanation: Given a list of prime numbers of length 4 primes = [2,7,13,19], the first 12 super ugly numbers The sequence is: [1,2,4,7,8,13,14,16,19,26,28,32].

Explanation:

  1. 1 is the super ugly number for any given primes.
  2. The numbers in the given primes are sorted in ascending order.
  3. 0 < k ≤ 100, 0 < n ≤ 106, 0 < primes[i] < 1000 。
  4. The nth super ugly number is guaranteed to be within the 32-bit signed integer range.

Solution: The dp idea is the same as the last ugly number, but the factor here becomes an array, so we also need an array to store the corresponding pointer position. It is worth mentioning that I originally used numbers to come Record the position, but due to the problem of duplication (due to the increase in the number of primes, there will be multiple factors that can be multiplied by the same next value, and these pointers must be +1 at this time), if the vector judgment is used, it will time out, So I thought of set, but the subscript of set cannot be recorded with integers, so iterator is used, here is also to consolidate the concept of pointer.

Code:

class Solution {
public:
    int nthSuperUglyNumber(int n, vector<int>& primes) {
        if(primes.empty()) return 0;
        int l = primes.size();
        set<int> dp;
        dp.insert(1);
        vector<set<int>::iterator> points;//point数组记录dp集合的迭代位置
        for(int i=0; i<l; i++)
            points.push_back(dp.begin());
        while(dp.size()<n){
            int minv = INT_MAX;
            int mini = 0;
            for(int i=0; i<l; i++) 
                minv = min(minv,*points[i]*primes[i]);//算出next值
            dp.insert(minv);
            for(int i=0; i<l; i++)
                if(*points[i]*primes[i]==minv) points[i]++;//迭代位置+1
        }
        return *dp.rbegin();//set的最后一位索引,取值。
    }
};

Set is not used much, this problem is to let me thoroughly understand the traversal of set and the use of iterators, and benefit a lot.

1201. Ugly Number III

Please help design a program to find the nth ugly number.

The ugly number is a positive integer divisible by a or b or c.

Example:

Input: n = 3, a = 2, b = 3, c = 5

Output: 4

Explanation: The sequence of ugly numbers is 2, 3, 4, 5, 6, 8, 9, 10 ... where the third one is 4 .

prompt:

  1. 1 <= n, a, b, c <= 10^9
  2. 1 <= a * b * c <= 10^18
  3. The result of this question is in the range of [1, 2 * 10 ^ 9]

Solution: The data range is 10 ^ 9, and it has nothing to do with dp. Although the name is still ugly =. =

Here is a direct reference to the solution of a great god. In fact, it is a mathematical problem, using the classic principle of tolerance.

Link: https://leetcode-cn.com/problems/ugly-number-iii/solution/er-fen-fa-si-lu-pou-xi-by-alfeim/

Code:

class Solution {
public:
    using LL = long long;
    int nthUglyNumber(int n, int a, int b, int c) {
        //看到n的范围应该马上联想到是,典型的二分思路
        LL low = min(min(a,b),c);                           //下边界显然是a、b、c中最小者
        LL high = static_cast<LL>(low) * n;                 //上边界是这个最小者的n倍    
        LL res = Binary_Search(low,high,a,b,c,n);
        LL left_a = res%a;
        LL left_b = res%b;
        LL left_c = res%c;
        return res - min(left_a,min(left_b,left_c));
    }
    //二分搜索
    LL Binary_Search(LL low,LL high,int a,int b,int c,LL n){
        if(low >= high) return low;
        LL mid = (low + high)>>1;
        LL MCM_a_b = MCM(a,b);
        LL MCM_a_c = MCM(a,c);
        LL MCM_b_c = MCM(b,c);
        LL MCM_a_b_c = MCM(MCM_a_b,c);
        //独立的丑数个数为,当前数分别除以a、b、c的和,减去当前数除以a、b、c两两间最小公倍数的和,再加上当前数除以 a、b、c三者的最小公倍数
        LL count_n = mid/a + mid/b + mid/c - mid/MCM_a_b - mid/MCM_b_c - mid/MCM_a_c +  mid/MCM_a_b_c;
        if(count_n == n) return mid;
        if(count_n < n) return Binary_Search(mid + 1,high,a,b,c,n);
        return Binary_Search(low,mid-1,a,b,c,n);
    }
    //求最小公倍数:两数乘积除以最大公约数
    LL MCM(LL a,LL b){
        LL Multi = a * b;
        while(b > 0){
            LL tmp = a % b;
            a = b;
            b = tmp;
        }
        return Multi/a;
    }
};
Published 13 original articles · won 27 · views 2649

Guess you like

Origin blog.csdn.net/u011708337/article/details/105105850