dp

class DP
{
public:
    DP();
    ~DP();

public:
    // 问题描述:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
    int jumpFloor(int number);

    // 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )
    // 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)
    // 问总共有多少条不同的路径?
    //https://leetcode-cn.com/problems/unique-paths/submissions/
    int uniquePaths(int m, int n);

    //给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
    //说明:每次只能向下或者向右移动一步。
    //https://leetcode-cn.com/problems/minimum-path-sum/
    int minPathSum(vector<vector<int>>& grid);

    //https://leetcode-cn.com/problems/edit-distance/
    //给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
    //  你可以对一个单词进行如下三种操作:
    //插入一个字符
    //删除一个字符
    //替换一个字符
    //来源:力扣(LeetCode)
    //链接:https ://leetcode-cn.com/problems/edit-distance
    int minDistance(string word1, string word2);

    //给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
    //  如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
    //  注意:你不能在买入股票前卖出股票。
    //  来源:力扣(LeetCode)
    //  链接:https ://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock
    //著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    int maxProfit(vector<int>& prices);

    //https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/
    //给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。
    //  你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。
    //  返回获得利润的最大值。
    //  注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。
    //定义二维数组 dp[n][2]dp[n][2]dp[n][2]:
    //  dp[i][0]dp[i][0]dp[i][0] 表示第 iii 天不持有可获得的最大利润;
    //  dp[i][1]dp[i][1]dp[i][1] 表示第 iii 天持有可获得的最大利润(注意是第 iii 天持有,而不是第 iii 天买入)。
    //  定义状态转移方程:
    //  不持有:dp[i][0] = max(dp[i?1][0], dp[i?1][1] + prices[i]?fee)dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee)dp[i][0] = max(dp[i?1][0], dp[i?1][1] + prices[i]?fee)
    //  对于今天不持有,可以从两个状态转移过来:1.昨天也不持有;2.昨天持有,今天卖出。两者取较大值。
    //  持有:dp[i][1] = max(dp[i?1][1], dp[i?1][0]?prices[i])dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i])dp[i][1] = max(dp[i?1][1], dp[i?1][0]?prices[i])
    //  对于今天持有,可以从两个状态转移过来:1.昨天也持有;2.昨天不持有,今天买入。两者取较大值。
    //  作者:sweetiee
    //  链接:https ://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/solution/jian-dan-dpmiao-dong-gu-piao-mai-mai-by-tejdo/
    //来源:力扣(LeetCode)
    //  著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    int maxProfit(vector<int>& prices, int fee);

    //309. 最佳买卖股票时机含冷冻期
    //  给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。​

    //  设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票) :

    //你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
    //  卖出股票后,你无法在第二天买入股票(即冷冻期为 1 天)。
//https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/
    int maxProfit3(vector<int>& prices);

    int maxProfit4(vector<int>& prices);


    //https://leetcode-cn.com/problems/isomorphic-strings/
    // 同构字符串
    //给定两个字符串 s 和 t,判断它们是否是同构的。
    //  如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。
    //  所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。
    //  来源:力扣(LeetCode)
    //  链接:https ://leetcode-cn.com/problems/isomorphic-strings
    bool isIsomorphic(string s, string t);

    //给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
    string longestPalindrome(string s);

    //给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
    int maxSubArray(vector<int>& nums);
};

int DP::jumpFloor(int number)
{
    if (number <= 2)
    {
        return number;
    }
    // 定义数组元素来保存历史数据
    int* dp = new int[number + 1];

    // 找出初始值
    dp[0] = 0;
    dp[1] = 1;
    dp[2] = 2;

    //通过关系式来计算出 dp[n]
    for (int n = 3; n <= number; n++)
    {
        dp[n] = dp[n - 1] + dp[n - 2];
    }
    return dp[number];
}

int DP::uniquePaths(int m, int n)
{
    if (m <= 0 || n <= 0)
    {
        return 0;
    }
    // 定义二位数组
    vector<vector<int> >dp(m, vector<int>(n));
    for (int i = 0; i < m; i++)
    {
        dp[i][0] = 1;
    }

    // 因为当m=0或n=0时,走的步数时固定的
    for (int i = 0; i < n; i++)
    {
        dp[0][i] = 1;
    }

    // 找到关系式,因为
    for (int i = 1; i < m; i++)
    {
        for (int j = 1; j < n; j++)
        {
            dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
        }
    }

    return dp[m - 1][n - 1];
}

int DP::minPathSum(vector<vector<int>>& grid)
{
    if (grid.size() <= 0 || grid[0].size() <= 0)
    {
        return 0;
    }
    int m = grid.size();
    int n = grid[0].size();

    // 关系式,和
    std::vector<std::vector<int>>dp(m, vector<int>(n));

    // dp[i][j]:走到i,j时的最小值
    // dp[i][j]=min(dp[i-1][j],dp[i][j-1]) + grid[i][j];
    // 找到关系式,因为当m=0 或n=0时不能使用这种关系式
    // 初始值
    dp[0][0] = grid[0][0];

    for (int i = 1; i < m; i++)
    {
        dp[i][0] = dp[i - 1][0] + grid[i][0];
    }

    for (int j = 1; j < n; j++)
    {
        dp[0][j] = dp[0][j - 1] + grid[0][j];
    }

    for (int i = 1; i < m; i++)
    {
        for (int j = 1; j < n; j++)
        {
            if (dp[i - 1][j] < dp[i][j - 1])
            {
                dp[i][j] = dp[i - 1][j] + grid[i][j];
            }
            else
            {
                dp[i][j] = dp[i][j - 1] + grid[i][j];
            }
        }
    }

    return dp[m - 1][n - 1];
}

int DP::minDistance(string word1, string word2)
{
    // 使用动态规划等的解法

    //1、定义动态数组的含义:
    // 若将cat变成cate,需要增加一个字符,或删除一个字符
    // 若将cat 变成fat,需要变换一个字符
    // 含义:通过分析知道,若将字符A的前i个字符,变换成字符B的前j个字符所需要的最少次数
    int m = word1.size();
    int n = word2.size();
    std::vector<std::vector<int>>dp(m + 1, std::vector<int>(n + 1));

    //2、找到数组之间的关系式
    // dp[i][j] = min(dp[i-1][j],dp[i][j-1]) + 1;
    // 若word1[i] = word2[j]则不需要变换,所以 dp[i][j]=dp[i-1][j-1]

    //3、初始值
    for (int i = 1; i < m + 1; i++)
    {
        dp[i][0] = dp[i - 1][0] + 1;
    }
    for (int j = 1; j < n + 1; j++)
    {
        dp[0][j] = dp[0][j - 1] + 1;
    }

    for (int i = 1; i < m + 1; i++)
    {
        for (int j = 1; j < n + 1; j++)
        {
            if (word1[i - 1] == word2[j - 1])
            {
                dp[i][j] = dp[i - 1][j - 1];
            }
            else
            {
                int a = dp[i - 1][j - 1];
                int b = dp[i - 1][j];
                int c = dp[i][j - 1];

                int temp = a < b ? a : b;
                dp[i][j] = (temp < c ? temp : c) + 1;
            }
        }
    }

    return dp[m][n];
}

int DP::maxProfit(vector<int>& prices, int fee)
{
    //1、动态数组第i天买入,第j天卖出的最大利润
    int m = prices.size();
    if (m <= 0)
    {
        return 0;
    }
    std::vector<std::vector<int>>dp(m, std::vector<int>(2));

    // 对股票有两种状态,持有的最大收益
    // 不持有的最大收益
    dp[0][0] = 0;// 第一天不持有
    dp[0][1] = -prices[0];//第一天持有

    for (int i = 1; i < m; i++)
    {
        dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee);
        dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);

    }
    return dp[m - 1][0];
}

int DP::maxProfit(vector<int>& prices)
{
    //int n = (int)prices.size(), ans = 0;
    //for (int i = 0; i < n; ++i) {
    //  for (int j = i + 1; j < n; ++j) {
    //      ans = max(ans, prices[j] - prices[i]);
    //  }
    //}
    //return ans;


    if (prices.empty())
    {
        return 0;
    }
    int max = 0;
    int min_pre = prices[0];
    for (int i = 1; i < prices.size(); i++)
    {
        if (min_pre > prices[i])
        {
            min_pre = prices[i];
        }

        if (max <= (prices[i] - min_pre))
        {
            max = prices[i] - min_pre;
        }

    }

    return max;
}

int DP::maxProfit3(vector<int>& prices)
{
    // 股票有三种状态的收益,买入,卖出,冷冻期
    int size = prices.size();
    if (size <= 0)
    {
        return 0;
    }
    vector<vector<int>>dp(size, vector<int>(3));

    dp[0][0] = -prices[0];
    dp[0][1] = 0;
    dp[0][2] = 0;

    for (int i = 1; i < size; i++)
    {
        // 考虑第i天持有股票的最大收益:第i-1天持有股票,不卖,或者第i-1天没有股票,买入
        dp[i][0] = max(dp[i - 1][0], dp[i - 1][2] - prices[i]);

        // 考虑第i天没有股票,且处于冷冻期,则只能是第i-1天,持有股票,并且卖了
        dp[i][1] = dp[i - 1][0] + prices[i];

        // 考虑第i天没有股票,且不处与冷冻期,所以,只能是第i-1天处于冷冻期,或第i-1天持有股票
        dp[i][2] = max(dp[i - 1][1], dp[i - 1][2]);
    }

    return max(dp[size - 1][1], dp[size - 1][2]);
}

int DP::maxProfit4(vector<int>& prices)
{

}

bool DP::isIsomorphic(string s, string t)
{
    unordered_map<char, char> s2t;
    unordered_map<char, char> t2s;
    int len = s.length();
    for (int i = 0; i < len; ++i) {
        char x = s[i], y = t[i];
        if ((s2t.count(x) && s2t[x] != y) || (t2s.count(y) && t2s[y] != x)) {
            return false;
        }
        s2t[x] = y;
        t2s[y] = x;
    }
    return true;
}

std::string DP::longestPalindrome(string s)
{
    //1、设字符串dp[i][j]:也就是s[i:j]是回文串
    // dp[i][j]=true  是回文串
    // dp[i][j]=false 不是回文串

    //2、找关系
    // 只有当 dp[i+1][j-1] 是回文串,且s[i]==s[j]时,dp[i][j] 才是回文串


    //3、边界条件
    // 当字符子串长度为1时 是回文串dp[0][0]=true
    // 当字符子串为长度为2时,若s[0]==s[1]时也是回文串

    // 4注意:在状态转移方程中,我们是从长度较短的字符串向长度较长的字符串进行转移的,因此一定要注意动态规划的循环顺序。

    int length = s.length();
    vector<vector<int>>dp(length, vector<int>(length));
    string max_sub_str;
    for (int l = 0; l < length; l++)
    {
        // 注意这里是i+l,因为子串长度为l
        for (int i = 0; i + l < length; i++)
        {
            int j = i + l;
            if (l == 0)
            {
                // 考虑子串长度为1
                dp[i][j] = true;
            }
            else if (l == 1)
            {
                // 子串长度为2
                dp[i][j] = (s[i] == s[j]);
            }
            else
            {
                dp[i][j] = (dp[i + 1][j - 1]) && (s[i] == s[j]);
            }

            // 获取最长的
            if (dp[i][j] && (l + 1 > max_sub_str.size()))
            {
                max_sub_str = s.substr(i, l + 1);
            }
        }
    }
    return max_sub_str;
}

int DP::maxSubArray(vector<int>& nums)
{
    // 动态规划的解法dp[i]=max{dp[i-1]+num[i],num[i]}
    // 其中dp[i]为以第i个结尾的连续数组的最大和
    // 然后取各个位置最大和的最大值
    int size = nums.size();
    int max_sum = nums[0];
    vector<int>dp(size);
    dp[0] = nums[0];
    for (int i = 1; i < size; i++)
    {
        dp[i] = max(dp[i - 1] + nums[i], nums[i]);

        if (dp[i] > max_sum)
        {
            max_sum = dp[i];
        }
    }
    return max_sum;
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容