回文串算法题

回文串是一个正着读和反着读顺序一样的字符串。"aba" 是回文串,"abba" 是回文串,"abc" 不是回文串。

回文串的题目,都要使用一个基本的逻辑,就是判断当前这个字符串是不是回文串。以 c++ 为例,代码如下。这种方法也可以称为双指针法,两个指针从字符串的两端向中间遍历每个字符,如果中间发现两个字符不相同,则不是回文字符串;遍历到最后,说明是回文串。

    bool isPalindrome(const string s) {
        int len = s.size();
        if (len <= 1) {
            return true;
        }

        int left = 0;
        int right = len - 1;
        while (left < right) {
            if (s[left] != s[right]) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }

双指针法,在其它数据结构题目中也会用到,比如链表中会用到快慢指针,也属于双指针。快速排序算法中,给选中的数据找到合适的位置,也会使用两个指针从两边向中间对数据进行遍历,也属于双指针。

判断回文串,也可以使用从中间向两边的方法,使用这种方法时,首先需要判断字符串的长度是奇数还是偶数,如果是奇数的话,那么两个指针从中间的位置开始向两边遍历;偶数的话,两个指针分别从中间两个元素的位置开始遍历。
没有特殊要求的话,优先选用从两边向中间的方式来判断一个字符串是不是回文串。

1 验证回文串

leetcode:验证回文串

题目要求判断给定的字符串是不是回文串,如果是回文串,则返回 true;如果原字符串不是回文串,那么最多可以删除一个字符,如果删除一个字符之后的字符串是回文串,那么返回 true,否则返回 false。

1.1 基础算法

(1)判断原字符串是不是回文串,是回文串返回 true;否则执行第 2 步

(2)遍历字符串的每个字符,分别将每个字符删除,判断删除字符之后的字符串是不是回文串。

如果是回文串,则返回 true,停止遍历;如果字符遍历结束,则返回 false。

这种算法的时间复杂度是 O(n 的平方),偏大,所以优先选用第二种方法,第二种算法的时间复杂度是 O(n)。

1.2 双指针,动态判断

(1)使用双指针,从两边向中间遍历每个字符

(2)如果遍历到两个字符不相等,则讨论如下两种情况

① 删除左边的字符,判断子串是不是回文串,是的话则返回 true

② 删除右边的字符,判断子串是不是回文串,是的话返回 true

如果两种情况都不是回文串,那么返回 false。

(3)如果字符串遍历结束,都满足回文串的要求,则返回 true

class Solution {
public:
    bool validPalindrome(string s) {
      int len = s.size();
      int left = 0;
      int right = len - 1;

      bool result = true;
      while (left < right) {
        if (s[left] != s[right]) {
            if (isPalindrome(s.substr(left + 1, right - left))) {
                return true;
            }

            if (isPalindrome(s.substr(left, right - left))) {
                return true;
            }
            return false;
        }
        left++;
        right--;
      }
      return true;
    }

    bool isPalindrome(const string s) {
        int len = s.size();
        if (len <= 1) {
            return true;
        }

        int left = 0;
        int right = len - 1;
        while (left < right) {
            if (s[left] != s[right]) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
};

2 最长回文子串

leetcode:最长回文子串

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

2.1 动态规划

将所有的子串的情况都遍历到,在遍历的过程中,判断子串是不是回文串,如果是回文串并且长度比已有的回文串长的话,那么就更新结果。属于动态规划算法。

这个算法的事件复杂度是 O(n 的平方),时间复杂度较高,在 leetcode 上运行时会超时。

class Solution {
public:
    string longestPalindrome(string s) {
      int size = s.size();
      for (int i = 0; i < size; i++) {
        for (int j = i; j < size; j++) {
            if (isPalindrome(s.substr(i, j - i + 1))) {
                if (j - i + 1 > max_length) {
                    max_length = j - i + 1;
                    max_str = s.substr(i, j - i + 1);
                }
            }
        }
      }
      return max_str;
    }


private:
    bool isPalindrome(string s) {
        int size = s.size();
        int i = 0;
        int j = size - 1;
        while (i < j) {
            if (s[i] != s[j]) {
                return false;
            }
            i++;
            j--;
        }
        return true;
    }

private:
    int max_length = 0;
    string max_str;
};

这个题目要找的是最长回文子串,我们能想到 j 的遍历从大向小遍历。这样遍历的话就是先遍历长度大的字符串,再遍历长度小的字符串。当第一个遍历到一个字符串是回文串,那么这个回文串就是长度最大的回文串,就可以直接返回。从小向大进行遍历,当遍历到这个字符串是回文串的时候,仍然不能返回,因为不能确定这个字符串是不是长度最大的回文串,需要将所有情况都遍历完毕才能确定最大的回文字符串。再进一步思考,我们可以以子串的长度作为遍历的依据,长度从大到小进行遍历。

如下是使用 c 语言实现的算法。

char ret[1001] = {'\0'};
char* longestPalindrome(char* s) {
    int length = strlen(s);
    if (length <= 1) {
        return s;
    }
    memset(ret, 0, 1001);
    for (int len = length; len >= 1; len--) {
        for (int i = 0; i < length; i++) {
            if (i + len - 1 >= length) {
                break;
            }

            int start_index = i;
            int end_index = i + len - 1;
            if (isPalindrome(s, start_index, end_index)) {
              int index = 0;
              for (int i = start_index; i <= end_index; i++) {
                ret[index] = s[i];
                index++;
              }
              return ret;
            }
        }
    }
    return NULL;
}

int isPalindrome(char *s, int start_index, int end_index) {
    while (start_index < end_index) {
        if (s[start_index] != s[end_index]) {
            return 0;
        }
        start_index++;
        end_index--;
    }
    return 1;
}

官方题解中也是遍历了子串的长度,但是是从小到大进行遍历的,同时还记录了已经遍历过的子串的结果。当判断长度较大的字符串是不是回文串时,可以直接基于历史记录来做判断。这也是动态规划常用的思路,就是在遍历的过程中记录历史信息,这样在后边的遍历中可以直接使用已经记录的历史信息。

官方题解中,正因为长度是从小到大进行遍历的,所以在遍历的时候判断字符串是不是回文串的时候,可以使用历史信息进行判断。因为 s[i][j] 比 s[i + 1][j - 1] 的长度要大,后者是不是回文串已经是确定的。

2.2 中心扩展法

leetcode 官方题解中提供了另外一种方法,中心扩展法。

这个问题的多种算法之间的区别就是遍历的对象不一样:

(1)两级遍历,遍历字符串的索引

(2)两级遍历,一级遍历子串的长度,一级遍历字符串的索引

(3)中心扩展法也是遍历字符串的索引,不过在计算逻辑上,是把索引当成了要遍历的子串的中心

class Solution {
public:
    string longestPalindrome(string s) {
      int size = s.size();
      int start = 0;
      int end = 0;
      for (int i = 0; i < size; i++) {
        int left1 = i;
        int right1 = i;
        int left2 = i;
        int right2 = i + 1;
        
        // 从中心向两边扩展,要考虑两种情况
        // 奇数的情况,偶数的情况
        centerExpand(s, left1, right1);
        centerExpand(s, left2, right2);
        if (right1 - left1 > end - start) {
            start = left1;
            end = right1;
        }

        if (right2 - left2 > end - start) {
            start = left2;
            end = right2;
        }
      }
      return s.substr(start, end - start + 1);
    }

    void centerExpand(string &s, int &left, int &right) {
        while (left >= 0 && right < s.size() && s[left] == s[right]) {
            left--;
            right++;
        }
        // 循环退出,说明最后一个索引不满足回文串的情况
        // 要么是 left 和 right 越界了,要么是当前这两个字符不相等
        // 这两种情况下,left 需要 ++, right 需要 --
        left++;
        right--;
    }

};

3 分割回文子串

leetcode:分割回文子串

本文,用基础的算法去思考的话,很难思考下去,遇到这种情况一般要考是不是可以使用递归算法。

class Solution {
public:
    vector<vector<string>> partition(string s) {
      partitionHelper(s, 0);
      return result_;
    }

    void partitionHelper(const string &s, int start_index) {
        int len = s.size();
        if (start_index >= len) {
            result_.push_back(one_instance_);
            return;
        }
        
        for (int i = start_index; i < len; i++) {
          if (isPalindome(s, start_index, i)) {
              one_instance_.push_back(s.substr(start_index, i - start_index + 1));
              partitionHelper(s, i + 1);
              one_instance_.pop_back();
          }
        }
    }

    bool isPalindome(const string &s, int start, int end) {
        if (start >= end) {
            return true;
        }

        if (flag[start][end] == 1) {
            return true;
        }
        if (flag[start][end] == -1) {
            return false;
        }

        int tmp_start = start;
        int tmp_end = end;
        while (tmp_start < tmp_end) {
            if (s[tmp_start] != s[tmp_end]) {
                flag[tmp_start][tmp_end] = -1;
                flag[start][end] = -1;
                return false;
            }
            tmp_start++;
            tmp_end--;
        }

        flag[start][end] = 1;
        return true;
    }

private:
  int flag[20][20] = {0};
  vector<vector<string>> result_;
  vector<string> one_instance_;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/670847.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

无限光年人工智能技术创新PMO负责人端煜受邀为第十三届中国PMO大会演讲嘉宾

全国PMO专业人士年度盛会 无限光年&#xff08;上海&#xff09;技术有限公司人工智能技术创新PMO负责人、原字节跳动朝夕光年PMO总监端煜先生受邀为PMO评论主办的2024第十三届中国PMO大会演讲嘉宾&#xff0c;演讲议题为“中国传统哲学在LLM企业项目管理应用中的思考与实践”。…

移植2D物理引擎到LVGL

背景 在LVGL交流群&#xff0c;有网友提出想要移植物理引擎到LVGL&#xff0c;遂有了本文。阅读本文需要对IDF和LVGL有所了解 过程 2D物理引擎有很多&#xff0c;经过一番调研选择了Chipmunk2D 下载源码 此处省略一万字&#xff0c;Github访问可能会有些慢 添加文件 将…

达梦8 内存泄漏泄漏原因分析之一

在实际使用过程中经常发现DMSERVER进程在OS中的内存占用使用远远超过实际情况。原因有很多&#xff0c;下面列出其中一种&#xff1a; 测试库版本 SQL> select id_code;LINEID ID_CODE ---------- ----------------------------------- 1 --03134283938-2022…

DPDK基础组件一(mbuf、ring、pktmbuf_pool)

一、rte_mbuf 此部分转自:https://zhuanlan.zhihu.com/p/616314276 1.mbuf结构 mbuf是报文中的描素的结构体,是整个转发过程中最核心的数据结构之一。主要针对于mbuf的常用API与基本原理做一个简单的介绍。 mbuf:报文内存存储结构,存储在mempool中mempool:使用环形缓冲…

如何选择D类音频放大器(数字功率放大器)

1 简介 多年来&#xff0c;音频内容一直在不断发展。从当地唱片店购买 12 英寸 LP 黑胶唱片的时代已经成为过去&#xff0c;现在我们通过流式传输几乎可即时播放云端的任何内容。虽然一些音频爱好者会为了获得新奇体验而重拾黑胶唱片&#xff0c;但今天绝大多数的音频都是以数…

基于Nginx和Consul构建自动发现的Docker服务架构——非常之详细

基于Nginx和Consul构建自动发现的Docker服务架构 文章目录 基于Nginx和Consul构建自动发现的Docker服务架构资源列表基础环境一、安装Docker1.1、Consul节点安装1.2、registrator节点安装 二、案例前知识点2.1、什么是Consul 三、基于Nginx和Consul构建自动发现的Docker服务架构…

[NOIP2015 提高组] 子串

题目背景 NOIP2015 Day2T2 题目描述 有两个仅包含小写英文字母的字符串 A A A 和 B B B。 现在要从字符串 A A A 中取出 k k k 个互不重叠的非空子串&#xff0c;然后把这 k k k 个子串按照其在字符串 A A A 中出现的顺序依次连接起来得到一个新的字符串。请问有多少…

从集合论到位运算

前言 本文将扫清位运算的迷雾&#xff0c;在集合论与位运算之间建立一座桥梁。 在高中&#xff0c;我们学了集合论&#xff08;set theory&#xff09;的相关知识。例如&#xff0c;包含若干整数的集合 S{0,2,3}。在编程中&#xff0c;通常用哈希表&#xff08;hash table&…

计算机网络学习2

文章目录 信道复用技术 第三章数据链路层概述数据链路层的三个重要问题封装成帧和透明传输差错检测可靠传输的相关基本概念可靠传输的实现机制停止等待协议回退N帧协议选择重传协议 点对点协议PPP共享式以太网网络适配器和MAC地址CSMA_CD协议的基本原理共享式以太网的争用期共享…

【计算机毕业设计】331基于微信小程序的家庭财务管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

开源VS闭源:大模型发展路径之争,你站哪一派?

文章目录 引言一、数据隐私1.1开源大模型的数据隐私1.2 闭源大模型的数据隐私1.3 综合考量 二、商业应用2.1 开源大模型的商业应用2.2 闭源大模型的商业应用2.3 商业应用的综合考量 三、社区参与3.1 开源大模型的社区参与3.2 闭源大模型的社区参与3.3 综合考量 结论 引言 在人…

数据库与数据库管理系统 MySQL的安装 SQL语言学习:DDL、DML

day51 数据库 数据库&#xff08;database&#xff09;就是一个存储数据的仓库。为了方便数据的存储和管理&#xff0c;它将数据按照特定的规律存储在磁盘上。 通过数据库管理系统&#xff0c;可以有效地组织和管理存储在数据库中的数据&#xff0c;如数据库管理系统MySQL 数据…

html three.js 引入.stl模型示例

1.新建一个模块用于放置模型 <div id"chart_map" style"width:800px;height:500px"></div> 2. 引入代码根据需求更改 <!-- 在head或body标签内加入以下链接 --> <script src"https://cdn.jsdelivr.net/npm/three0.137/build/t…

c++的string一键介绍

前言&#xff1a; 这篇文章旨在帮助读者回忆如何使用string&#xff0c;并提醒注意事项。它不是一篇详细的功能介绍&#xff0c;而是一篇润色文章。 先展示重载函数&#xff0c;如果该函数一笔不可带过&#xff0c;就先展示英文原档&#xff08;附带翻译&#xff09;&#xf…

基于语音信号MFCC特征提取和GRNN神经网络的人员身份检测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 MFCC特征提取 4.2 GRNN神经网络概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ...............................................…

Django序列化器中is_valid和validate

今天上班的时候分配了一个任务&#xff0c;是修复前端的一个提示优化&#xff0c;如下图所示&#xff1a; 按照以往的经验我以为可以直接在validate上进行校验&#xff0c;如何抛出一个异常即可 &#xff0c;例如&#xff1a; class CcmSerializer(serializers.ModelSerialize…

HALCON-从入门到入门-软件界面介绍

1.废话 从halcon12到halcon23&#xff0c;开发的IDE界面大差不差&#xff0c;简单说下界面上不同功能按键的分布&#xff0c;以及一些快捷键啥的&#xff0c;要是还有我没有总结到的&#xff0c;又比较好用的&#xff0c;欢迎大家补充一下。 1.菜单栏 从上看到下&#xff0c;…

大型医疗器械企业四套系统数据集成技术干货分享

在大型医疗企业中&#xff0c;数据的互联互通是提升运营效率和数据利用率的关键。本次分享将概述如何通过轻易云集成平台将金蝶ERP、ZOHO CRM、泛微OA和汇联易报销系统进行高效联动&#xff0c;展示在实施过程中积累的技术干货。 某大型医疗企业&#xff0c;专注于麻醉和呼吸医…

系统架构设计师 - 操作系统(1)

操作系统 操作系统&#xff08;5-6分&#xff09;操作系统概述进程管理进程和线程的基本概念进程的状态 ★前趋图 ★★★★信号量与 PV 操作 ★★★★死锁及银行家算法 ★ 大家好呀&#xff01;我是小笙&#xff0c;本章我主要分享系统架构设计师 - 操作系统(1)知识&#xff0c…

B站如何屏蔽短视频:成都鼎茂宏升文化传媒公司

B站如何屏蔽短视频&#xff1a;优化你的观看体验 在当今数字化时代&#xff0c;B站&#xff08;哔哩哔哩&#xff09;作为国内领先的弹幕视频网站&#xff0c;以其丰富的视频资源和独特的弹幕文化吸引了大量用户。然而&#xff0c;随着短视频的兴起&#xff0c;B站也引入了短视…