动态规划问题

1. 最长回文子串(LeetCode 5)

问题描述:

给定一个字符串,找出最长的回文子串。

解题思路:

使用动态规划建立一个二维表格dp[i][j],表示子串S[i:j+1]是否为回文串。根据dp[i][j]的值来决定dp[i][j+1]的值。

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

// 检查字符串s[i:j+1]是否为回文串
bool isPalindrome(char *s, int i, int j) {
    while (i < j) {
        if (s[i] != s[j]) return false;
        i++;
        j--;
    }
    return true;
}

// 动态规划求解最长回文子串
char* longestPalindrome(char* s) {
    int len = strlen(s);
    if (len == 0) return "";

    int dp[len][len];
    memset(dp, 0, sizeof(dp));

    int start = 0; // 记录最长回文子串的起始位置
    int maxLength = 1; // 记录最长回文子串的长度

    // 单字符回文串
    for (int i = 0; i < len; i++) {
        dp[i][i] = 1;
    }

    // 双字符回文串
    for (int i = 0; i < len - 1; i++) {
        if (s[i] == s[i + 1]) {
            dp[i][i + 1] = 1;
            start = i;
            maxLength = 2;
        }
    }

    // 长于2个字符的回文串
    for (int length = 3; length <= len; length++) {
        for (int i = 0; i < len - length + 1; i++) {
            int j = i + length - 1;
            if (s[i] == s[j] && dp[i + 1][j - 1]) {
                dp[i][j] = 1;
                start = i;
                maxLength = length;
            }
        }
    }

    char* result = (char*)malloc((maxLength + 1) * sizeof(char));
    strncpy(result, s + start, maxLength);
    result[maxLength] = '\0';
    return result;
}

int main() {
    char s[] = "babad";
    char* result = longestPalindrome(s);
    printf("Longest Palindromic Substring: %s\n", result);
    free(result);
    return 0;
}

2. 编辑距离(牛客网)

问题描述:

给定两个字符串,求将一个字符串转换成另一个字符串所需的最少操作数(插入、删除、替换)。

解题思路:

使用二维动态规划表格dp[i][j],表示word1[0:i-1]word2[0:j-1]的编辑距离。根据插入、删除、替换操作更新dp[i][j]

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// 动态规划求解编辑距离
int minDistance(char* word1, char* word2) {
    int m = strlen(word1);
    int n = strlen(word2);
    int dp[m + 1][n + 1];

    for (int i = 0; i <= m; i++) {
        for (int j = 0; j <= n; j++) {
            if (i == 0) {
                dp[i][j] = j;
            } else if (j == 0) {
                dp[i][j] = i;
            } else {
                int cost = (word1[i - 1] == word2[j - 1]) ? 0 : 1;
                dp[i][j] = fmin(fmin(dp[i - 1][j] + 1, dp[i][j - 1] + 1), dp[i - 1][j - 1] + cost);
            }
        }
    }

    return dp[m][n];
}

int main() {
    char word1[] = "intention";
    char word2[] = "execution";
    printf("Edit Distance: %d\n", minDistance(word1, word2));
    return 0;
}

3. 最大子数组和(牛客网)

问题描述:

给定一个整数数组,找出具有最大和的连续子数组。

解题思路:

使用一维动态规划数组dp,其中dp[i]表示以第i个元素结尾的最大子数组和。递推关系为dp[i] = max(dp[i-1] + nums[i], nums[i])

#include <stdio.h>
#include <limits.h>

// 动态规划求解最大子数组和
int maxSubArray(int* nums, int numsSize) {
    int maxSum = nums[0];
    int currentSum = nums[0];

    for (int i = 1; i < numsSize; i++) {
        currentSum = fmax(nums[i], currentSum + nums[i]);
        maxSum = fmax(maxSum, currentSum);
    }

    return maxSum;
}

int main() {
    int nums[] = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
    int size = sizeof(nums) / sizeof(nums[0]);
    printf("Maximum Subarray Sum: %d\n", maxSubArray(nums, size));
    return 0;
}

4. 最长递增子序列(牛客网)

问题描述:

给定一个整数数组,找到其中最长递增子序列的长度。

解题思路:

使用一维动态规划数组dp,其中dp[i]表示以第i个元素结尾的最长递增子序列的长度。递推关系为dp[i] = max(dp[j] + 1),其中j < inums[j] < nums[i]

#include <stdio.h>
#include <limits.h>

// 动态规划求解最长递增子序列
int lengthOfLIS(int* nums, int numsSize) {
    if (numsSize == 0) return 0;

    int dp[numsSize];
    int length = 1;
    dp[0] = 1;

    for (int i = 1; i < numsSize; i++) {
        dp[i] = 1;
        for (int j = 0; j < i; j++) {
            if (nums[i] > nums[j] && dp[i] < dp[j] + 1) {
                dp[i] = dp[j] + 1;
            }
        }
        if (length < dp[i]) {
            length = dp[i];
        }
    }

    return length;
}

int main() {
    int nums[] = {10, 9, 2, 5, 3, 7, 101, 18};
    int size = sizeof(nums) / sizeof(nums[0]);
    printf("Length of Longest Increasing Subsequence: %d\n", lengthOfLIS(nums, size));
    return 0;
}

5. 0-1 胶囊问题(牛客网)

问题描述:

给定一个背包的容量和一组物品的重量及价值,求最大总价值。

解题思路:

使用二维动态规划表格dp[i][w],表示前i个物品中背包容量为w时的最大价值。递推关系为dp[i][w] = max(dp[i-1][w], dp[i-1][w-weight[i]] + value[i])

#include <stdio.h>
#include <string.h>
#include <algorithm>

#define MAX_ITEMS 100
#define MAX_CAPACITY 100

// 动态规划求解0-1背包问题
int knapsack(int weight[], int value[], int n, int capacity) {
    int dp[MAX_ITEMS][MAX_CAPACITY] = {0};

    for (int i = 1; i <= n; i++) {
        for (int w = 0; w <= capacity; w++) {
            if (weight[i-1] <= w) {
                dp[i][w] = std::max(dp[i-1][w], dp[i-1][w-weight[i-1]] + value[i-1]);
            } else {
                dp[i][w] = dp[i-1][w];
            }
        }
    }
    return dp[n][capacity];
}

int main() {
    int weight[] = {1, 2, 3};
    int value[] = {60, 100, 120};
    int n = sizeof(weight) / sizeof(weight[0]);
    int capacity = 5;

    printf("Maximum value in Knapsack = %d\n", knapsack(weight, value, n, capacity));
    return 0;
}

6. 矩阵的最小路径和(牛客网)

问题描述

给定一个二维矩阵 grid,每个格子里有一个非负整数。你需要从矩阵的左上角 (0,0) 开始,移动到右下角 (m-1,n-1),每次只能向右或向下移动一步,计算从左上角到右下角的最小路径和。

输入

  • 一个 m x n 的二维矩阵 grid,其中 grid[i][j] 表示第 i 行第 j 列的格子的值。

输出

  • 从左上角到右下角的最小路径和。

示例

输入:

[
[1, 3, 1],
[1, 5, 1],
[4, 2, 1]
]

输出:

7

解释:

最优路径是:1 → 3 → 1 → 1 → 1,总路径和为 7。

解题思路

这个问题可以使用动态规划(DP)解决。定义一个二维数组 dp,其中 dp[i][j] 表示从起点到 (i, j) 的最小路径和。状态转移方程如下:

  • 如果只考虑从上方和左方的移动:
    • dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1])

其中 dp[i-1][j] 是从上方来的路径和,dp[i][j-1] 是从左方来的路径和。

#include <stdio.h>
#include <limits.h>

#define MAX_ROWS 100
#define MAX_COLS 100

// 动态规划求解矩阵的最小路径和
int minPathSum(int grid[MAX_ROWS][MAX_COLS], int m, int n) {
    int dp[MAX_ROWS][MAX_COLS];

    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++) {
            dp[i][j] = grid[i][j] + (dp[i-1][j] < dp[i][j-1] ? dp[i-1][j] : dp[i][j-1]);
        }
    }

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

int main() {
    int grid[MAX_ROWS][MAX_COLS] = {
        {1, 3, 1},
        {1, 5, 1},
        {4, 2, 1}
    };
    int m = 3, n = 3;

    printf("Minimum Path Sum: %d\n", minPathSum(grid, m, n));
    return 0;
}
相关推荐
凌肖战1 分钟前
力扣上刷题之C语言实现(数组)
c语言·算法·leetcode
秋夫人28 分钟前
B+树(B+TREE)索引
数据结构·算法
梦想科研社1 小时前
【无人机设计与控制】四旋翼无人机俯仰姿态保持模糊PID控制(带说明报告)
开发语言·算法·数学建模·matlab·无人机
Milo_K1 小时前
今日 leetCode 15.三数之和
算法·leetcode
Darling_001 小时前
LeetCode_sql_day28(1767.寻找没有被执行的任务对)
sql·算法·leetcode
AlexMercer10121 小时前
【C++】二、数据类型 (同C)
c语言·开发语言·数据结构·c++·笔记·算法
Greyplayground1 小时前
【算法基础实验】图论-BellmanFord最短路径
算法·图论·最短路径
蓑 羽1 小时前
力扣438 找到字符串中所有字母异位词 Java版本
java·算法·leetcode
源代码:趴菜1 小时前
LeetCode63:不同路径II
算法·leetcode·职场和发展
儿创社ErChaungClub2 小时前
解锁编程新境界:GitHub Copilot 让效率翻倍
人工智能·算法