前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • JavaScript Part 1

    • Ajax总结篇
    • Canvas 绘制八大行星
    • DOM编程之API学习总结篇
    • JavaScript事件机制
    • JavaScript代码片段100个
    • JavaScript作用域分析总结
    • JavaScript原型链回顾
    • JavaScript及jQuery中的各种宽高属性图解
    • JavaScript工程项目的一系列最佳实践
    • JavaScript常用API合集
    • JavaScript数组、字符串、对象常用方法
    • JavaScript数组方法总结篇
    • JavaScript深浅拷贝
    • JavaScript运动框架之速度时间版本
    • JavaScript运行机制Event Loop
    • JavaScript防抖节流原理
    • Javascript中的复制粘贴功能
    • Javascript数组详解
    • OOP之原型与原型链
    • Object.defineProperty详解
    • V8源码浅析JS数组常见方法
    • await 在 forEach 中不生效解决方案
    • iframe+表单跨域提交POST请求
    • javascript笔记总结篇
    • 业务中处理数据结构常用的JS方法
    • 作用域
    • 你真的掌握变量和类型了吗
    • 前后端分离之数据Mock
    • 原型与原型链
    • 原生JS补给(上)
    • 如何写出一个惊艳面试官的深拷贝
    • 带你填一些JS容易出错的坑
    • 彻底弄懂 JavaScript 执行机制
    • 执行上下文 执行栈
    • 正则回顾总结
    • 正则基础知识
    • 正则完整篇
    • 正则表达式
    • 浅析Promise原理
    • 浅谈JavaScript中的异步处理
    • 深拷贝 vs 浅拷贝
    • 聊一聊typeof instanceof 实现原理.
    • 聊一聊闭包
    • 高阶函数map reduce filter
  • JavaScript Part 2

  • CSS

  • HTML

  • Jquery

  • ES6

  • 小程序

  • Vue

  • React

  • 深入React

  • React Native

  • NodeJS

  • Angular

  • TypeScript

  • Webpack

  • 浏览器

  • 移动端

  • 前端工程化

  • Electron

  • HTTP

  • Nginx

  • Linux

  • 数据结构与算法

  • LeetCode算法题

  • 综合

完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

最长回文子串|博客系列

# 题目描述

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 一🌰:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
@前端进阶之旅: 代码已经复制到剪贴板

示例二🌰:

输入: "aafddfa"
输出: "afddfa"
@前端进阶之旅: 代码已经复制到剪贴板

示例三🌰:

输入: "abda"
输出: "a"
注意: "abda"并不是回文字符串,"abba"才是
@前端进阶之旅: 代码已经复制到剪贴板

所谓回文字符串就比如是:“上海自来水来自海上”,正读反读都是一样的。

# 解题思路1

暴力破解法:

(不推荐)

  1. 将输入的字符串转换为数组;
  2. 嵌套两层for循环遍历数组,比较每一种情况下的字符串与它的反转字符串是否相同,若是相同则表明它为回文;
  3. 比较出长度最长的回文子串。

暴力解决法最容易理解,但是所需的时间复杂度太大,在leetCode上允许只通过了一半的测试用例,因此不推荐使用。

# coding1

/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function(s) {
    if (!s) return ''
    if (s.length <= 1) return s
    let sArr = s.split(''),
        maxStrs = [],
        currentStrs = [];
    for (let i = 0; i < sArr.length; i++) {
        for (let j = i; j < sArr.length; j++) {
            currentStrs = sArr.slice(i, j + 1)
            if (currentStrs.join('') === currentStrs.reverse().join('')) {
                maxStrs = maxStrs.length > currentStrs.length ? maxStrs : currentStrs
            }
        }
    }
    return maxStrs.join('')
};
@前端进阶之旅: 代码已经复制到剪贴板

# 解题思路2

三、中心扩展法:

(相对容易理解且效率高)

我们观察到回文中心的两侧互为镜像。因此,回文可以从它的中心展开,并且只有 2n−1 个这样的中心。

为什么中心是2n-1而不是n ? 比如有字符串abcba,这时回文子串是abcba,中心是c;

又有字符串adccda,这时回文子串是adccda,中心是cc。

由此可见中心点既有可能是一个字符,也有可能是两个字符,当中心为一个字符的时候有n个中心,当中心为两个字符的时候有n-1个中心,所以一共有2n-1个中心。

  1. 考虑字符串长度为0和1的情况;
  2. 考虑字符串长度为2的情况,若为2则判断这个字符串是不是回文字符串;
  3. for循环字符串,比较第i项和第i+1项是否相同(s[i]是否等于s[i+1]);
  4. 若是相同则表示s[i] + s[i+1]为偶数的回文中心,因此应该继续比较i-1和i+2项;比如给定字符串abba,i为1时,我们已经知道了s[i] + s[i+1],此时应该以bb为中心向左右进行扩展比较s[i-1]和s[i+2]项;
  5. 若是不同则表示字符串可能是为寄数的回文中心,因此应该以s[i]为中心向左右进行扩展比较s[i-1]和s[i+1]项;
  6. 每次for循环中比较上面得到的寄数回文字符串和偶数回文字符串,取较长的;
  7. 每次for循环中比较之前记录下最长的回文字符串和这次的回文字符串,取较长的;
  8. for 循环之后即可得到最长回文字符串;

中心扩展法的核心就是通过找到回文中心,然后以该中心向左右两边扩展来查找。

复杂度分析

时间复杂度:O(n^2),由于围绕中心来扩展回文会耗去 O(n) 的时间,所以总的复杂度为 O(n^2)

空间复杂度:O(1)。

# coding2

/**
* @param {string} s
* @return {string}
*/
var longestPalindrome = function (s) {
    if (!s) return ''
    if (s.length === 1) return s;
    if (s.length === 2) return s[0] === s[1] ? s : s[1];
    let maxStr = '',
        len = s.length;
    for (let i = 0; i < len; i++) {
        let even = '', // 定义偶数中心回文
            odd = ''; // 定义奇数中心回文
        if (s[i] === s[i + 1]) { // 若是偶数中心回文
            let evenIndex = center(s, i - 1, i + 2); // 比较中心的前一项和后一项
            even = s.slice(evenIndex.left, evenIndex.right)
        }
        let oddIndex = center(s, i - 1, i + 1); // 奇数中心回文
        odd = s.slice(oddIndex.left, oddIndex.right);
        let longer = even.length > odd.length ? even : odd; // 比较奇、偶
        maxStr = maxStr.length > longer.length ? maxStr : longer
    }
    return maxStr
}
// 中心扩展
function center(s, left, right) {
    let len = s.length;
    while (left >= 0 && right < len && s[left] === s[right]) {
        left--;
        right++;
    }
    return { left: left + 1, right: right }
}
@前端进阶之旅: 代码已经复制到剪贴板

← 最长公共前缀盛最多水的容器 →

fe
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • JavaScript Part 1

    • Ajax总结篇
    • Canvas 绘制八大行星
    • DOM编程之API学习总结篇
    • JavaScript事件机制
    • JavaScript代码片段100个
    • JavaScript作用域分析总结
    • JavaScript原型链回顾
    • JavaScript及jQuery中的各种宽高属性图解
    • JavaScript工程项目的一系列最佳实践
    • JavaScript常用API合集
    • JavaScript数组、字符串、对象常用方法
    • JavaScript数组方法总结篇
    • JavaScript深浅拷贝
    • JavaScript运动框架之速度时间版本
    • JavaScript运行机制Event Loop
    • JavaScript防抖节流原理
    • Javascript中的复制粘贴功能
    • Javascript数组详解
    • OOP之原型与原型链
    • Object.defineProperty详解
    • V8源码浅析JS数组常见方法
    • await 在 forEach 中不生效解决方案
    • iframe+表单跨域提交POST请求
    • javascript笔记总结篇
    • 业务中处理数据结构常用的JS方法
    • 作用域
    • 你真的掌握变量和类型了吗
    • 前后端分离之数据Mock
    • 原型与原型链
    • 原生JS补给(上)
    • 如何写出一个惊艳面试官的深拷贝
    • 带你填一些JS容易出错的坑
    • 彻底弄懂 JavaScript 执行机制
    • 执行上下文 执行栈
    • 正则回顾总结
    • 正则基础知识
    • 正则完整篇
    • 正则表达式
    • 浅析Promise原理
    • 浅谈JavaScript中的异步处理
    • 深拷贝 vs 浅拷贝
    • 聊一聊typeof instanceof 实现原理.
    • 聊一聊闭包
    • 高阶函数map reduce filter
  • JavaScript Part 2

  • CSS

  • HTML

  • Jquery

  • ES6

  • 小程序

  • Vue

  • React

  • 深入React

  • React Native

  • NodeJS

  • Angular

  • TypeScript

  • Webpack

  • 浏览器

  • 移动端

  • 前端工程化

  • Electron

  • HTTP

  • Nginx

  • Linux

  • 数据结构与算法

  • LeetCode算法题

  • 综合