【代码随想录】【算法训练营】【第50天】 [1143]最长公共子序列 [1035]不相交的线 [53]买卖股票的最佳时机III [392]判断子序列

前言

思路及算法思维,指路 代码随想录
题目来自 LeetCode

day 50,周三,无法坚持~

题目详情

[1143] 最长公共子序列

题目描述

1143 最长公共子序列
1143 最长公共子序列

解题思路

前提:最长公共子序列,元素的相对顺序一致
思路:动态规划 dp[i][j]:以字符串text1 [0, i-1]和字符串txtx2 [0, j-1]的最长公共子序列的长度, if (text1[i-1] == text2[j-1]) dp[i][j] = dp[i-1][j-1] + 1; else dp[i][j] = max(dp[i-1][j], dp[i][j-1])
重点:递推公式的推导、dp数组初始化

代码实现

C语言
动态规划
// 动态规划 dp[i][j]:以字符串text1 [0, i-1]和字符串txtx2 [0, j-1]的最长公共子序列的长度
// if (text1[i-1] == text2[j-1]) dp[i][j] = dp[i-1][j-1] + 1
// else dp[i][j] = max(dp[i-1][j], dp[i][j-1])

int maxFun(int p1, int p2)
{
    return p1 > p2 ? p1 : p2;
}

int longestCommonSubsequence(char* text1, char* text2) {
    int text1_len = strlen(text1);
    int text2_len = strlen(text2);
    int dp[text1_len + 1][text2_len + 1];
    // dp数组初始化
    for (int m = 0; m <= text1_len; m++) {
        dp[m][0] = 0;
    }
    for (int n = 1; n <= text2_len; n++) {
        dp[0][n] = 0;
    }
    // 遍历
    for (int i = 1; i <= text1_len; i++) {
        for (int j = 1; j <= text2_len; j++) {
            if (text1[i - 1] == text2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            } else {
                dp[i][j] = maxFun(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }
    return dp[text1_len][text2_len];
}

[1035] 不相交的线

题目描述

1035 不相交的线
1035 不相交的线

解题思路

前提:转化为求最长公共子数组,且数组元素相对顺序保持一致
思路:动态规划 dp[i][j]: nums1 [0, i-1]和nums2 [0, j-1]的最长公共数组的长度, if (nums1[i-1] == nums2[j-1]) dp[i][j] = dp[i-1][j-1] + 1; else dp[i][j] = maxFun(dp[i-1][j], dp[i][j-1])
重点:递推公式的推导、dp数组初始化

代码实现

C语言
动态规划
// 动态规划 dp[i][j]: nums1 [0, i-1]和nums2 [0, j-1]的最长公共数组的长度
// if (nums1[i-1] == nums2[j-1]) dp[i][j] = dp[i-1][j-1] + 1
// else dp[i][j] = maxFun(dp[i-1][j], dp[i][j-1])

int maxFun(int p1, int p2)
{
    return p1 > p2 ? p1 : p2;
}

int maxUncrossedLines(int* nums1, int nums1Size, int* nums2, int nums2Size) {
    int dp[nums1Size + 1][nums2Size + 1];
    // dp初始化
    for (int m = 0; m <= nums1Size; m++) {
        dp[m][0] = 0;
    }
    for (int n = 1; n <= nums2Size; n++) {
        dp[0][n] = 0;
    }
    // 遍历
    for (int i = 1; i <= nums1Size; i++) {
        for (int j = 1; j <= nums2Size; j++) {
            if (nums1[i - 1] == nums2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            } else {
                dp[i][j] = maxFun(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }
    return dp[nums1Size][nums2Size];
}

[53] 最大子数组和

题目描述

53 最大子数组和
53 最大子数组和

解题思路

前提:最大连续子数组的和
思路:动态规划 dp[i]: 以数组的子数组[0, i]以i为结尾的最大连续子数组的和,dp[i]有两种情况: nums[i]加入子数组中; 从nums[i]重新计算,dp[i] = max(dp[i-1]+nums[i], nums[i])
重点:递推公式的推导、dp数组初始化

代码实现

C语言
动态规划
// 动态规划 dp[i]: 以数组的子数组[0, i]以i为结尾的最大连续子数组的和
// dp[i]有两种情况: nums[i]加入子数组中; 从nums[i]重新计算
// dp[i] = max(dp[i-1]+nums[i], nums[i])

int maxFun(int p1, int p2)
{
    return p1 > p2 ? p1 : p2;
}

int maxSubArray(int* nums, int numsSize) {
    int dp[numsSize];
    int result = 0;
    // dp初始化
    dp[0] = nums[0];
    result = dp[0];
    // 遍历
    for (int i = 1; i < numsSize; i++) {
        dp[i] = maxFun(dp[i - 1] + nums[i], nums[i]);
        result = maxFun(dp[i], result);
    }

    return result;
}
贪心
int maxSubArray(int* nums, int numsSize) {
    int sum = 0;
    int slow = 0;
    int fast = 0;
    int maxSum = -10001;
    while (fast < numsSize) {
        // 连续和为负数时,抛弃当前连续子数组和
        if (sum < 0) {
            sum = 0;
        }
        sum += nums[fast];
        // 取最大和
        if (sum > maxSum) {
            maxSum = sum;
        }
        fast++;
    }
    return maxSum;
}

[392] 判断子序列

题目描述

392 判断子序列
392 判断子序列

解题思路

前提:化为求最长公共子序列,元素的相对顺序一致,判断最长公共子序列的长度是否与s的长度相等
思路:动态规划 dp[i][j]: 字符串s [0, i-1]和字符串t [0, j-1]的最长公共子序列,if (s[i - 1] == t[j - 1]) dp[i][j] = dp[i-1][j-1] + 1; if (s[i - 1] != t[j - 1]) dp[i][j] = dp[i][j-1],判断最长公共子序列的长度是否等于sLen
重点:递推公式的推导、dp数组初始化

代码实现

C语言
动态规划
// 动态规划 dp[i][j]: 字符串s [0, i-1]和字符串t [0, j-1]的最长公共子序列
// if (s[i - 1] == t[j - 1]) dp[i][j] = dp[i-1][j-1] + 1
// if (s[i - 1] != t[j - 1]) dp[i][j] = dp[i][j-1], 此时仅可以删除t字符串中的元素
// 判断最长公共子序列的长度是否等于sLen

bool isSubsequence(char* s, char* t) {
    int sLen = strlen(s);
    int tLen = strlen(t);
    int dp[sLen + 1][tLen + 1];
    // dp初始化
    for (int m = 0; m <= sLen; m++) {
        dp[m][0] = 0;
    }
    for (int n = 1; n <= tLen; n++) {
        dp[0][n] = 0;
    }
    // 遍历
    for (int i = 1; i <= sLen; i++) {
        for (int j = 1; j <= tLen; j++) {
            if (s[i - 1] == t[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] +1;
            } else {
                dp[i][j] = dp[i][j - 1];
            }
        }
    }
    return dp[sLen][tLen] == sLen;
}
双指针
// 双指针

bool isSubsequence(char* s, char* t) {
    int sLen = strlen(s);
    int tLen = strlen(t);
    int slow = 0;
    int fast = 0;
    int count = 0;
    while ((slow < sLen) && (fast < tLen)) {
        if (s[slow] == t[fast]) {
            count++;
            slow++;
        }
        fast++;
    }
    return count == sLen;
}

今日收获

  1. 动态规划
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值