Coding Practice,48天强训(10)

Topic 1:最长回文子串(动态规划、manacher、中心扩展算法)

这种题一般解决就是三个解法——动态规划、马拉车(manacher)算法、中心扩展算法,但是马拉车算法不通用,只能解决这一道题,应用价值不高,可以以后再了解,动态规划的方法倒是通用,还能知道所有字符的回文情况,但空间复杂度比较高,这里还是用中心扩展法

class Solution {
public:
    // 从中心向两边扩展,返回以left和right为中心的最长回文长度
    int exp(const string& s, int left, int right) 
    {
        while (left >= 0 && right < s.size() && s[left] == s[right]) // 不会越界,越界检查条件在前
        {
            left--;   // 向左扩展
            right++;  // 向右扩展
        }
        return right - left - 1; // 返回回文长度 (right - left - 1)  a b a 
    }

    int getLongestPalindrome(string A) {
        if (A.empty()) return 0;
        
        int start = 0, end = 0;  // 记录最长回文子串的起始和结束位置
        for (int i = 0; i < A.size(); i++) 
        {
            int len1 = exp(A, i, i); // 奇数长度回文,中心为i
            int len2 = exp(A, i, i + 1);// 偶数长度回文,中心为i和i+1

            int len = max(len1, len2);// 取两种情况的较大值

            if (len > end - start) // 如果找到更长的回文,更新起始和结束位置
            {
                start = i - (len - 1) / 2;  // 计算回文起始,整数除法,可以带进去算算,奇偶数都正确
                end = i + len / 2;          // 计算回文结束
            }
        }

        return end - start + 1;
    }
};
Topic 2:买卖股票的最好时机(一)(动态规划、贪心)

由于题目时间轴和一次交易的特性,可以作图

图中红色部分表示在对应两天中,所作交易产生的利润,绿色为如果在此间交易,会承担的亏损,如果不限交易次数,那么我们收集所有的红色交易部分,即可获取11天交易的最大利润。

但是现在限制我们只能交易1次,那么我们不需要关注所有获利交易,只需要按照时间轴,从左往右找获利交易中的最小值,固定最小值,然后让后续的价格与之相减,拿到最大价值,若发现新最小值,则更新最小值,并重复计算,不断更新最大价值,最后留下来的就是全局所能得到的最大价值,即可求出该区间中买卖的最好时机,这是贪心的思路。后续还有动态规划的方法,那个是通用解法,有时间要用DP再做一遍;

class Solution {
  public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param prices int整型vector
     * @return int整型
     */
    int maxProfit(vector<int>& prices) 
    {
        if (prices.size() <= 1) return 0;

        int min_price = INT_MAX;// 股价最低点
        int max_profit = 0;// 最大价值

        for (int price : prices) 
        {
            if (price < min_price) 
            {
                min_price = price;// 发现还有更低点,则更新
            } 
            else if (price - min_price > max_profit) // 否则查看当前价值-最低点是否大于之前记录的最大价值
            {
                max_profit = price - min_price;// 如果大于就更新最大价值
            }
        }

        return max_profit;
    }
};

再简化一下

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.size() <= 1) return 0;

        int min_price = INT_MAX;// 股价最低点
        int max_profit = 0;// 最大价值

        for (int price : prices) 
        {
            min_price = min(min_price, price);// 发现还有更低点,则更新
            max_profit = max(max_profit, price - min_price);// 如果大于就更新最大价值
        }

        return max_profit;
    }
};

Topic 3:过河卒(动态规划)

经典的动态规划,dp[n,m]——走到坐标n,m所有的路径数

dp[n,m] = dp[n - 1, m] + dp[n,m - 1],递推公式,很简单就能想到

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n, m, x, y;
    cin >> n >> m >> x >> y;

    vector<vector<bool>> blocked(21, vector<bool>(21, false));    //记录马的封锁区 数组大小20 + 1覆盖所有可能的坐标
    
    if (x >= 0 && x <= n && y >= 0 && y <= m) // 马的位置
    {
        blocked[x][y] = true;
    }
    // 马的控制点,也可以用公式法 if (abs(x1 - x) + abs(y1 - y) == 3 && x1 != x && y1 != y)
    int dx[] = {1, 1, -1, -1, 2, 2, -2, -2};
    int dy[] = {2, -2, 2, -2, 1, -1, 1, -1};

    for (int i = 0; i < 8; ++i) 
    {
        int nx = x + dx[i];
        int ny = y + dy[i];
        if (nx >= 0 && nx <= n && ny >= 0 && ny <= m) 
        {
            blocked[nx][ny] = true;
        }
    }

    vector<vector<long long>> dp(21, vector<long long>(21, 0));
    dp[0][0] = 1; // 起点

    for (int i = 0; i <= n; ++i) 
    {
        for (int j = 0; j <= m; ++j) 
        {
            if (blocked[i][j]) 
            {
                continue; // 跳过马的控制点
            }
            if (i == 0 && j == 0) 
            {
                continue; // 起点已初始化
            }
            if (i > 0) 
            {
                dp[i][j] += dp[i - 1][j];
            }
            if (j > 0)
            {
                dp[i][j] += dp[i][j - 1];
            }
        }
    }

    cout << dp[n][m] << endl;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值