动态规划(1)

2023-11-16

动态规划(Dynamic Programming)是一种具有分治思想的迭代技术,它用于求解某些复杂的不包含决策过程的最优化问题,其基本思路是将原问题分解为子问题,并保存子问题的求解结果,从而避免不必要的重复计算。动态规划的主要思想就是将复杂的问题分解成一系列子问题,依次求解子问题,最后将子问题的结果组合起来,达到总体最优解的目的。

解决此类问题的重要思路:

1)  找到状态转移方程

2)  要确定好初始值

3)找到边界条件

给你一个字符串 s,找到 s 中最长的回文子串。

如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。


示例 2:

输入:s = "cbbd"
输出:"bb"

提示:

1 <= s.length <= 1000
s 仅由数字和英文字母组成

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-palindromic-substring

        下面我们来分析一下这题,如果字符串的长度为1,则就是最长字串,如果长度大于2的话要另外考虑。

我们定义一个二维数组 dp[i][j],其中 dp[i][j] 表示字符串从索引 i 到索引 j 的子串是否为回文子串。根据回文子串的定义,我们知道如果一个字符串是回文的,那么去掉它的首尾字符后仍然是回文的。

根据以上分析,我们可以得出以下状态转移方程:

dp[i][j]  =  (s[i] == s[j])  &&  ( dp[i + 1][j - 1] )

其中,dp[i + 1][j - 1] 表示字符串从索引 i + 1j - 1 的子串是否为回文子串。

根据状态转移方程,我们需要从长度较短的子串开始计算,逐步扩展子串的长度,直到得到最终的结果。

具体的算法步骤如下:

  1. 初始化一个二维数组 dp,将所有 dp[i][i](长度为 1 的子串)都设为 true
  2. 初始化最长回文子串的长度 maxLen 和起始位置 start,初始值为 1 和 0。
  3. 从长度为 2 的子串开始遍历,逐步增加子串的长度 L,遍历范围为 L = 2L = len,其中 len 是字符串的长度。
  4. 对于每个子串的起始位置 i,计算子串的结束位置 j,即 j = i + L - 1。若 s[i] 等于 s[j],则根据状态转移方程计算 dp[i][j],(在此处有个小细节,当i - j < 3时候并且s[i] = s[j],即子串只有两个字符,且这两个字符相等的时候,也是符合回文的要求)
  5. dp[i][j]true,并且子串的长度 L 大于 maxLen,则更新 maxLenstart
  6. 最终,根据 maxLenstart 找到最长回文子串,并返回该子串。

具体的代码实现如下:

(c语言)

char* longestPalindrome(char* s) {
    int len = strlen(s);
    if (len < 2) {
        return s;
    }
    int dp[1000][1000];
    int maxLen = 1;
    int start = 0;  // 记录最长回文子串的起始位置

    // 先全部初始化,认为长度为 1 的都是回文子串
    for (int i = 0; i < len; i++) {
        dp[i][i] = 1;
    }

    // 从小开始,长度 L 等于 2
    for (int L = 2; L <= len; L++) {
        // 从左边开始
        for (int i = 0; i < len; i++) {
            // 确定右边的边界 j - i + 1 = L
            int j = L + i - 1;
            if (j >= len) {
                break;
            }

            // 判断左右字符是否相等
            if (s[i] != s[j]) {
                dp[i][j] = 0;
            } else {
                //长度为2的回文串
                if (j - i < 3) {
                    dp[i][j] = 1;
                } else {
                    //转移方程
                    dp[i][j] = dp[i + 1][j - 1];
                }
            }

            // 如果当前子串是回文且长度大于最长回文子串长度
            if (dp[i][j] == 1 && j - i + 1 > maxLen) {
                maxLen = j - i + 1;
                start = i;
            }
        }
    }

    // 创建动态数组存储结果
    char* result = (char*)malloc((maxLen + 1) * sizeof(char));
    strncpy(result, s + start, maxLen);
    result[maxLen] = '\0';

    return result;
}

(java语言)

public class Solution {
    public String longestPalindrome(String s) {
        int len = s.length();
        if (len < 2) {
            return s;
        }

        int maxLen = 1;
        int begin = 0;
        // dp[i][j] 表示 s[i..j] 是否是回文串
        boolean[][] dp = new boolean[len][len];
        // 初始化:所有长度为 1 的子串都是回文串
        for (int i = 0; i < len; i++) {
            dp[i][i] = true;
        }

        char[] charArray = s.toCharArray();
        // 递推开始
        // 先枚举子串长度
        for (int L = 2; L <= len; L++) {
            // 枚举左边界,左边界的上限设置可以宽松一些
            for (int i = 0; i < len; i++) {
                // 由 L 和 i 可以确定右边界,即 j - i + 1 = L
                int j = L + i - 1;
                // 如果右边界越界,就可以退出当前循环
                if (j >= len) {
                    break;
                }

                if (charArray[i] != charArray[j]) {
                    dp[i][j] = false;
                } else {
                    if (j - i < 3) {
                        dp[i][j] = true;
                    } else {
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                }

                // 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
                if (dp[i][j] && j - i + 1 > maxLen) {
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        // 根据起始位置和最大长度截取最长回文子串
        return s.substring(begin, begin + maxLen);
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

动态规划(1) 的相关文章

随机推荐

  • Pygame - 背景图片连续滚动

    方法 让背景图像分别在 0 0 和 0 img heigh 两个位置向下移动它们 当其中一个位于 0 img heigth 位置时 再次将其放置在 0 img heigh 位置 具体代码 import pygame import sys i
  • vue跳转微信小程序遇到的坑

    官方参考https developers weixin qq com doc offiaccount OA Web Apps Wechat Open Tag html 21 vue项目 h5跳转小程序 简书 遇到的问题 在PC端不显示样式
  • 力扣(LeetCode)算法_C++——最大连续 1 的个数 III

    给定一个二进制数组 nums 和一个整数 k 如果可以翻转最多 k 个 0 则返回 数组中连续 1 的最大个数 示例 1 输入 nums 1 1 1 0 0 0 1 1 1 1 0 K 2 输出 6 解释 1 1 1 0 0 1 1 1 1
  • PSA wiring diagram for jumper/relay 2.2hdi

    Anyone has 2007 Citroen Relay 2 2 HDI 88 KW 4HU engine and need an engine and abs wiring diagrams ECU Vistion DCU 102 Ju
  • c#线程三

    1 单元模式和Windows Forms 单元模式线程是一个自动线程安全机制 非常贴近于COM Microsoft的遗留下的组件对象模型 尽管 NET最大地放弃摆脱了遗留下的模型 但很多时候它也会突然出现 这是因为有必要与旧的API 进行通
  • 使用FPGA进行加速运算

    注 本篇文章来源于知乎 为微软亚洲研究院李博杰的回答 详细链接在这儿 点击打开链接 在这篇文章中 作者从CPU GPU FPGA的架构出发 讨论了微软数据中心为什么使用FPGA而不选择GPU 该文章是我逐字搬运过来的 其目的是为后续我们公司
  • XView小程序开源组件库

    XView小程序开源组件库 XView小程序组件库本着简单易用的原则封装组件 使用时只需要在json配置文件中引用即可 使用 组件库当中大致可分为一下三大类 布局组件 基础组件 表单组件 XView小程序组件库本着简单易用的原则封装组件 使
  • UI自动化概念 + Web自动化测试框架介绍

    1 UI自动化测试概念 我们先明确什么是UI UI 即 User Interface简称UI用户界面 是系统和用户之间进行交互和信息交换的媒介 UI自动化测试 Web自动化测试和移动自动化测试都属于UI自动化测试 UI自动化测试就是借助自动
  • tf2使用tensorboard(jupyter notebook)

    环境 tensorflow2 0 jupyter notebook unbuntu18 04 这个应该影响不大 示例 用的是iris数据集分类 该数据集库自带 import tensorflow as tf import numpy as
  • Catalan卡塔兰数

    今天在二叉搜索树 随机组成情况 分析复杂度遇到 catalan数 学习并记录一下 背景 分析二叉搜索树 BST 的平均性能时 我们可以分为随机生成和随机组成分析 随机生成 将各节点按照数的顺序随机排列 若含有n个节点 n个互异关键码 则有n
  • 波士顿动力开源代码_失去动力两年后,我如何开始开源之旅

    波士顿动力开源代码 by Hemakshi Sachdev 通过Hemakshi Sachdev 失去动力两年后 我如何开始开源之旅 How I started my open source journey after being demo
  • 数据结构(一)顺序表、链表以及队列

    一 顺序表 顺序表 它具有连续内存地址 访问方便O 1 但是删除和插入不方便O N 常用数组实现 在JAVA中 声明一个数组直接使用语句 int array new int k k为已知的数组大小 当然JAVA中本身自带了很多封装的数组 如
  • 全国地区代码表

    天津市 地区代码 地区名称 1100 天津市 辽宁省 地区代码 地区名称 2210 沈阳市 2210 法库县 2210 康平县 2210 辽中县 2210 新民市 2220 大连市 2222 普兰店市 2223 庄河市 2224 瓦房店市
  • 晶振电路中为什么用22pf或30pf

    让我们一起来看看到底晶振电路中为什么用22pf或30pf的电容而不用别的了 Y1是晶体 相当于三点式里面的电感 C1和C2就是电容 5404非门和R1实现一个NPN的三极管 接下来分析一下这个电路 5404必需要一个电阻 不然它处于饱和截止
  • js获取元素的距离父元素、窗口的距离offsetTop,offsetHeight,clientHeight

    前言 相信很多项目中都会有这样一个小需求 PC端 移动端则是点击 鼠标移上某个菜单或者某个位置 显示一个弹出框 移开则隐藏弹出框 就是css中hover效果 这种通常做法是每个子菜单下都有一个弹框 父元素相对定位 子元素绝对定位 只需要控制
  • 14、Qt 捕捉鼠标事件

    0 需求 在鼠标进入窗口实时捕捉所在位置 以及进行的操作 1 方法 我们主要使用QWidget中的几个方法 鼠标进入 void enterEvent QEvent event 鼠标离开 void leaveEvent QEvent even
  • 管理一年,领悟一生:迷茫、洞见与成长

    领导力跟你做了多少年管理 管过多少人 没有直接的关系 你开悟了 一年就能管得井井有条 不开悟 十年也是一塌糊涂 1 引言 大家好 我是苍何 相信作为技术人的成长路线大家都有了解吧 大家普遍所了解的就是两个路线 技术管理和架构师 而成为架构师
  • ue4大气纹理

    UE4的大气纹理 在 class FAtmosphereTextures public FRenderResource 成员变量上涉及到了辐射 投射 和散射 分三个部分 首先放入一个commandlist 然后分别就各参数创建RTT 传参数
  • python 中关于推导式生成器的一些总结

    推导式 可以理解为是数据生成方式或者是处理方式 类型 列表 元组 字符串 字典 集合 外部包装的括号决定了返回值类型的 定义 列表推导式 表达式 for循环 if语句 1 对列表中的每项元素进行立方运算 变换功能 a 1 2 3 4 5 6
  • 动态规划(1)

    动态规划 Dynamic Programming 是一种具有分治思想的迭代技术 它用于求解某些复杂的不包含决策过程的最优化问题 其基本思路是将原问题分解为子问题 并保存子问题的求解结果 从而避免不必要的重复计算 动态规划的主要思想就是将复杂