面试150——第八周

目录

零钱兑换

三角形最小路径之和

最小路径和

不同路径二

最长回文子串

交错字符串

编辑距离

[买卖股票的最佳时机 III](#买卖股票的最佳时机 III)

[买卖股票的最佳时机 IV](#买卖股票的最佳时机 IV)

最大正方形


零钱兑换

解法:完全背包

记得是找最小兑换个数,初始化为 0x3f3f3f3,不然会栈溢出

cpp 复制代码
class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        if(amount == 0)
        {
            return 0;
        }
        int n = coins.size();
        vector<vector<int>> dp(n + 1, vector<int>(amount + 1, 0x3f3f3f3f));
        for(int i = 0; i <= n; i++)
        {
            dp[i][0] = 0;
        }
        for(int i = 1;i <= n; i++)
        {
            for(int j = 1; j <= amount; j++)
            {
                dp[i][j] = dp[i-1][j];
                if(j >= coins[i-1])
                {
                    dp[i][j] = min(dp[i][j],dp[i][j-coins[i-1]] + 1);
                }
            }
        }
        return dp[n][amount] == 0x3f3f3f3f ? -1:dp[n][amount];
    }
};

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        if(amount == 0)
        {
            return 0;
        }
        int n = coins.size();
        vector<int> dp(amount + 1, 0x3f3f3f3f);
        dp[0] = 0;
        for(int i = 1;i <= n; i++)
        {
            for(int j = 1; j <= amount; j++)
            {
                if(j >= coins[i-1])
                {
                    dp[j] = min(dp[j],dp[j-coins[i-1]] + 1);
                }
            }
        }
        return dp[amount] == 0x3f3f3f3f ? -1:dp[amount];
    }
};

解法二:贪心 + 二分

cpp 复制代码
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        vector<int> ret;
        for(int i = 0; i < n; i++)
        {
            if(ret.size() == 0 || ret.back() < nums[i])
            {
                ret.push_back(nums[i]);
            }
            else
            {
                int l = 0, r = ret.size() - 1;
                while(l < r)
                {
                    int mid = l + (r - l) / 2;
                    if(ret[mid] < nums[i])
                    {
                        l = mid + 1;
                    }
                    else
                    {
                        r = mid;
                    }
                }
                ret[l] = nums[i];
            }
        }
        return ret.size();
    }
};

三角形最小路径之和

解法:动态规划

二维动态规划,根据题目所给条件构建动态转移方程来解决,注意列j的取值范围

cpp 复制代码
class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        int n = triangle.size();
        vector<vector<int>> dp(n + 1,vector<int>(n + 1, 0x3f3f3f3f));
        dp[0][0] = 0;
        int ret = 0x3f3f3f3f;
        for(int i = 1;i <= n;i++)
        {
            for(int j = 1;j <=i; j++)
            {
                dp[i][j] = min(dp[i-1][j],dp[i-1][j-1]) + triangle[i-1][j-1];
                if(i == n)
                {
                    ret = min(ret,dp[i][j]);
                }
            }
        }
        return ret;
    }
};

最小路径和

解法:动态规划

路径问题的二维dp模型:取上和左的值来求最小路径和

cpp 复制代码
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int n = grid.size(), m =grid[0].size();
        vector<vector<int>> dp(n + 1, vector<int>(m + 1, INT_MAX));
        dp[0][1] = 0;
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= m; j++)
            {
                dp[i][j] = min(dp[i-1][j], dp[i][j - 1]) + grid[i-1][j-1];
            }
        }
        return dp[n][m];
    }
};

不同路径二

解法:动态规划

与上题思路类似

cpp 复制代码
class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int n = obstacleGrid.size(), m =obstacleGrid[0].size();
        vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
        dp[0][1] = 1;
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= m; j++)
            {
                if(obstacleGrid[i - 1][j - 1] == 0)
                {
                    dp[i][j] = dp[i-1][j] + dp[i][j-1];
                }
            }
        }
        return dp[n][m];
    }
};

最长回文子串

解法:动态规划

使用dpij 来表示:s 的【i,j】位置构成的子串是否是回文串,再进行遍历找最长的

cpp 复制代码
class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        vector<vector<bool>> dp(n,vector<bool>(n,false));
        for(int i = n - 1; i >=0 ; i--)
        {
            for(int j = i; j < n ; j++)
            {
                if(s[i] == s[j])
                {
                    if(i == j || i + 1 == j || dp[i + 1][j - 1])
                    {
                        dp[i][j] = true;
                    }
                }
                
            }
        }
        string ret;
        int len = 0;
        for(int i = 0; i < n; i++)
        {
            for(int j = i; j < n; j++)
            {
                if(dp[i][j] && len < j - i + 1)
                {
                    len = max(len, j - i + 1);
                    ret = s.substr(i, len);
                }
            }
        }
        return ret;
    }
};

交错字符串

解法:动态规划

往二维dp字符串的思路上想

cpp 复制代码
class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
        int n = s1.size(), m = s2.size(), k = s3.size();
        if(n + m != k)
        {
            return false;
        }
        vector<vector<bool>> dp(n + 1, vector<bool>(m + 1, false));
        s1 = " " + s1,s2 = " " + s2,s3 = " " + s3;
        dp[0][0] = true;
        for(int i = 1; i <= n; i++)
        {
            if(s1[i] != s3[i]) break;
            else dp[i][0] = true;
        }
        for(int j = 1; j <= m; j++)
        {
            if(s2[j] != s3[j]) break;
            else dp[0][j] = true;
        }
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= m; j++)
            {
            if((dp[i-1][j] && s1[i] == s3[i + j]) || (dp[i][j-1] && s2[j] == s3[i + j]))
            {
                dp[i][j] = true;
            }
            }
        }
        return dp[n][m];
    }
};
// 一维很多坑
class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
        int n = s1.size(), m = s2.size(), k = s3.size();
        if(n + m != k)
        {
            return false;
        }
        vector<bool> dp(m + 1, false);
        s1 = " " + s1,s2 = " " + s2,s3 = " " + s3;
        dp[0] = true;
        // for(int i = 1; i <= n; i++)
        // {
        //     if(s1[i] != s3[i]) break;
        //     else dp[i][0] = true;
        // }
        for(int j = 1; j <= m; j++)
        {
            //if(s2[j] != s3[j]) break;
            if(s2[j] != s3[j] || dp[j - 1] == false) break;
            else dp[j] = true;
        }
        for(int i = 1; i <= n; i++)
        {
            // 放在填表中更新第一行
            dp[0] = dp[0] && (s1[i] == s3[i]);
            // dp[i][0] = dp[i-1][0] && (s1[i] == s3[i]);
            for(int j = 1; j <= m; j++)
            {
                if((dp[j] && (s1[i] == s3[i + j])) || (dp[j-1] && (s2[j] == s3[i + j])))
                {
                    dp[j] = true;
                }
                else
                {
                    // 还要加上else判断。。。。
                    dp[j] = false;
                }
            }
        }
        return dp[m];
    }
};

编辑距离

解法:动态规划

注意初始化

cpp 复制代码
class Solution {
public:
    int minDistance(string word1, string word2) {
        int n = word1.size(), m = word2.size();
        vector<vector<int>> dp(n + 1,vector<int>(m + 1));
        // 初始化 0表示空串
        for(int i = 0; i <= n; i++)
        {
            dp[i][0] = i;
        }
        for(int j = 0; j <= m; j++)
        {
            dp[0][j] = j;
        }

        for(int i = 1; i <= n; i++)
        {
            for(int j = 1;j <=m; j++)
            {
                if(word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1];
                else
                {
                    dp[i][j] = min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1])) + 1;
                }
            }
        }
        return dp[n][m];
    }
};

买卖股票的最佳时机 III

买卖股票的最佳时机 IV

解法:动态规划

做了n多次,到这里还是实现出来有点问题,空悲切··

cpp 复制代码
// 3 换 k+1 解决IV问题
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        vector<vector<int>> bug(n, vector<int>(3, -0x3f3f3f3f));
        vector<vector<int>> solt(n, vector<int>(3,-0x3f3f3f3f));
        bug[0][0] = -prices[0];
        solt[0][0] = 0;
        for(int i = 1; i < n; i++)
        {
            for(int j = 0; j < 3; j++)
            {
                bug[i][j] = max(bug[i-1][j], solt[i-1][j] - prices[i]);
                solt[i][j] = solt[i-1][j];
                if(j-1>=0)
                {
                    solt[i][j] = max(solt[i][j],bug[i-1][j-1] + prices[i]);
                }
            }
        }
        int ans=0;
        for(int j = 0; j < 3; j++)
        {
            ans = max(ans, solt[n-1][j]);
        }
        return ans;
    }
};

最大正方形

解法:动态规划

状态定义:dpij 表示 当前正方形的最大边长;怎么得到?

上 左 左上角的正方形的最大边长的最小值,但是还要判断是否可以跟当前位置进行结果:当前位置为1,可以跟最小值 + 1 组成更大的;为0就只能为0,结果都结果不了

cpp 复制代码
class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        int n = matrix.size(), m = matrix[0].size();
        int ret = 0;
        vector<vector<int>> dp(n+1,vector<int>(m+1,INT_MAX));
        for(int i=0;i<n;i++) dp[i][0]=0;
        for(int j=0;j<m;j++) dp[0][j]=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(matrix[i-1][j-1] == '1')
                {
                    dp[i][j] = min(dp[i-1][j],min(dp[i][j-1],dp[i-1][j-1])) + 1;
                }
                else
                {
                    dp[i][j] = 0;
                }
                ret = max(ret,dp[i][j] * dp[i][j]);
            }
        }
        return ret;
    }
};

以上便是全部内容,有问题欢迎在评论区指正,感谢观看!