王清欢Randy 王清欢Randy
首页
  • 编程语言

    • C/C++ 学习笔记
    • Golang 学习笔记
  • 算法分析

    • LeetCode 刷题笔记
  • 操作系统

    • Linux 基础
    • Vim 实用技巧
    • Shell 脚本编程
    • GDB 学习笔记
  • 开发工具

    • Git 学习笔记
  • 分布式理论

    • 共识算法
    • 分布式事务
  • 数据库内核

    • PostgreSQL
    • Postgres-XL
  • hidb
  • pgproxy
  • 实用技巧
  • 学习方法
  • 资源分享
GitHub (opens new window)
首页
  • 编程语言

    • C/C++ 学习笔记
    • Golang 学习笔记
  • 算法分析

    • LeetCode 刷题笔记
  • 操作系统

    • Linux 基础
    • Vim 实用技巧
    • Shell 脚本编程
    • GDB 学习笔记
  • 开发工具

    • Git 学习笔记
  • 分布式理论

    • 共识算法
    • 分布式事务
  • 数据库内核

    • PostgreSQL
    • Postgres-XL
  • hidb
  • pgproxy
  • 实用技巧
  • 学习方法
  • 资源分享
GitHub (opens new window)
  • 基础算法

    • 双指针

      • 双指针基础
      • 碰撞指针
      • 快慢指针
      • 滑动窗口
    • 二分查找

      • 基础应用
      • 边界收缩
      • 局部有序
    • 排序算法

      • 01八大排序
      • 02快速排序
      • 03归并排序
      • 04桶排序
      • 05堆排序
    • 优先搜索

      • 01递归
      • 02网格结构深度优先搜索
      • 03树结构深度优先搜索
      • 04图结构深度优先搜索
      • 05网格结构广度优先搜索
      • 06树结构广度优先搜索
      • 07图结构广度优先搜索
    • 回溯算法

      • 01递归
      • 02 子集问题
      • 03 全排列问题
      • 04 组合问题
      • 05 回溯搜索问题
  • 基础数据结构

    • 线性表与哈希表

      • 01数组
      • 02栈和队列
      • 03单调栈
      • 04优先队列
      • 05双端队列
      • 06哈希表
      • 07多重集合
      • 08前缀和
      • 09数据结构设计
    • 字符串

      • 01字符串比较
      • 02回文字符串
        • 02 回文字符串
          • 125 验证回文串
          • 680 验证回文字符串 Ⅱ
          • 647 回文子串
          • 409 最长回文串
          • 5 最长回文子串
      • 03字符串匹配
      • 04字符串算术表达式
    • 单链表

      • 01链表基础操作
      • 02链表遍历
    • 二叉树

      • 01二叉树的属性
      • 02二叉树的操作
      • 03层次遍历
      • 04前中后序遍历
      • 05二叉搜索树的属性
      • 06二叉搜索树的操作
      • 07字典树
      • 08二叉搜索树BST
    • 图

      • 01二分图
      • 02拓扑排序
      • 03并查集
      • 04最小生成树
      • 05最短路径
  • 进阶算法

    • 贪心算法

      • 01跳跃游戏
      • 02分配问题
      • 03区间问题
    • 分治策略

    • 动态规划

      • 01一维动态规划
      • 02二维动态规划
      • 03分割型动态规划
      • 04子序列问题
      • 05背包问题
      • 06字符串编辑问题
      • 07股票交易问题
  • 其他内容

    • 数学问题

      • 01公倍数与公因数
      • 02质数问题
      • 03进制转换问题
      • 04数字字符串求和问题
      • 05众数问题
      • 06中位数问题
      • 07数字处理问题
      • 08随机数问题
    • 位运算

      • 01位运算基础
      • 02妙用异或运算
      • 03二进制特性
  • LeetCode刷题笔记
  • 基础数据结构
  • 字符串
王清欢
2023-03-24
目录

02回文字符串

# 02 回文字符串

# 125 验证回文串 (opens new window)

给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。

输入一个字符串,输出一个布尔值表示该字符串是否为回文串

输入: "A man, a plan, a canal: Panama"
输出: true
解释:"amanaplanacanalpanama" 是回文串

解析:

​ 回文串一般都可以采用双指针从两头向中间检验,或者采用中心扩展法从中间向两头验证是否为回文串。

​ 本题可以采用双指针的策略,从字符串首尾两端逐个字符检验。但是本题中给出的字符串有许多非字母字符,可以用一个新字符串保存原字符串中的所有字母小写形式,然后对其使用双指针方法验证。

class Solution {
public:
    bool isPalindrome(string s) {
        // 筛选出字母内容
        string sgood;
        for (char ch: s) {
            if (isalnum(ch)) {
                sgood += tolower(ch);
            }
        }
        // 双指针验证回文串
        int n = sgood.size();
        int left = 0, right = n - 1;
        while (left < right) {
           if (sgood[left] != sgood[right]) {
                return false;
            }
            ++left;
            --right;
        }
        return true;
    }
};

# 680 验证回文字符串 Ⅱ (opens new window)

给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。

输入一个字符串,输出一个布尔值表示该字符串是否能通过删除操作构成回文串

输入: s = "abca"
输出: true
解释: 你可以删除c字符。

解析:

​ 本题采用双指针的方法检验回文串,两个指针分别指向字符串的头和尾,逐一比较两个指针指向的元素。当出现两个指针指向的字符不想等的情况时分别检验将头指针指向的元素删除和将尾指针指向的元素删除两种情况下继续比较字符,是否仍然可以构成回文串。

class Solution {
public:
    bool subPalindrome(string s, int head, int tail){
        for(;head<tail;++head,--tail){
            if(s[head]!=s[tail]){
                return false;
            }
        }
        return true;
    }

    bool validPalindrome(string s) {
        int head = 0, tail = s.size()-1;
        while(head<tail){
            if(s[head]==s[tail]){
                ++head;
                --tail;
            }else{
                if( subPalindrome(s,head,tail-1)||subPalindrome(s,head+1,tail)){
                    return true;
                }else{
                    return false;
                }
            }
        }
        return true;
    }
};

# 647 回文子串 (opens new window)

给定一个字符串,求其有多少个回文子字符串。回文的定义是左右对称。

输入是一个字符串,输出一个整数,表示回文子字符串的数量。

输入:s = "aaa"
输出:6
解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"

解析:

​ 本题采用中心扩展法,可以从字符串的每个位置开始,向左向右延长,判断存在多少以当前位置为中轴的回文子字符串。中心扩展法:枚举每一个可能的回文中心,然后用两个指针分别向左右两边拓展,当两个指针指向的元素相同的时候就拓展,否则停止拓展。枚举过程中要区分子串的长度为偶数情况和奇数情况。

class Solution {
public:
    int countCurSub(string s, int lsh, int rsh){
        int count = 0;
        while(lsh>=0 && rsh<s.length() && s[lsh]==s[rsh]){
            --lsh;
            ++rsh;
            ++count;
        }
        return count;
    }

    int countSubstrings(string s) {
        int ans = 0;
        for(int i=0;i<s.length();++i){
            // 长度为奇数的回文子串
            ans += countCurSub(s,i,i);
            // 长度为偶数的回文子串
            ans += countCurSub(s,i,i+1);
        }
        return ans;
    }
};

# 409 最长回文串 (opens new window)

给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。

输入一个字符串,输出一个整数表示可组成的最长回文串长度

输入: "abccccdd"
输出: 7
解释: 可以构造的最长的回文串是"dccaccd", 它的长度是 7。

解析:

​ 本题采用哈希表辅助统计给出字符串中每个字符频次,频次为偶数的可以全部加入构成回文串,频次为奇数的减去一个剩下的也可以加入构成回文串。需要注意的是如果有奇数频次的字符,那么构成的回文串总长可以为奇数,该字符可以出现在回文串中心。

class Solution {
public:
    int longestPalindrome(string s) {
        unordered_map<char,int> chCnt;
        for(const auto ch: s){
            ++chCnt[ch];
        }
        bool hasOdd = false;
        int ans = 0;
        for(const auto [key,cnt]: chCnt){
            if(cnt&1){
                ans+=(cnt-1);
                hasOdd = true;
            }else{
                ans+=cnt;
            }
        }
        return hasOdd?ans+1:ans;
    }
};

# 5 最长回文子串 (opens new window)

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

输入一个字符串,输出一个字符串表示最长回文子串

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

解析:

​ 本题和647 回文子串 (opens new window)相似,可以采用中心扩展法寻找最长回文子串。分别考虑子串长度为奇数和偶数的情况,奇数的中心只有一个,偶数长度的中心为 i 和 i+1;以此中心使用两个指针分别向左向右扩展,逐一比较两个指针指向元素的值是否相等;出现不等情况时,使用一个pair对象返回已经检验的回文子串的起始位置和结束位置。

​ 遍历所有回文子串,比较子串的长度,不断更新较长回文子串的起始和结束位置,最终使用substr()方法切片获得最长回文子串。

class Solution {
public:
    pair<int,int> subStr(string s, int lsh, int rsh){
        while(lsh>=0 && rsh<s.length() &&s[lsh]==s[rsh]){
            --lsh;
            ++rsh;
        }
        return {lsh+1,rsh-1};
    }

    string longestPalindrome(string s) {
        int start = 0, end=0;
        for(int i=0; i<s.length();++i){
            pair<int,int> oddStr = subStr(s,i,i);
            pair<int,int> evenStr = subStr(s,i,i+1);
            if(oddStr.second-oddStr.first > end-start){
                start = oddStr.first;
                end = oddStr.second;
            }
            if(evenStr.second-evenStr.first > end-start){
                start = evenStr.first;
                end = evenStr.second;
            }
        }
        return s.substr(start,end-start+1);
    }
};
上次更新: 2023/11/19, 12:55:48
01字符串比较
03字符串匹配

← 01字符串比较 03字符串匹配→

Theme by Vdoing | Copyright © 2023-2024 Wang Qinghuan | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式