leetcode刷题之回文链表and最长回文子串

文章介绍了三种判断单链表是否为回文的方法,包括通过快慢指针分割并反转链表、将链表元素存入数组再对比以及直接数组首尾对比。此外,还讨论了回文数的判断和最长回文子串的求解,提供了中心扩展法和动态规划两种解决方案。
摘要由CSDN通过智能技术生成

234.回文链表

方法一:找中间结点,断开链表,后一段链表进行反转

思路:①找中间结点:使用快慢指针fast,slow,fast每次走两个,slow每次走一个;
如果链表的个数是奇数个,那么最后slow指向中间节点
如果链表的个数是偶数个,那么最后slow指向中间两个节点的后一个
②使用prev指针保存slow的前一个结点,然后prev.next = null 将链表分成前后两段
③将后一段链表进行反转,然后两段链表进行比对
在这里插入图片描述

/**
 * @param {ListNode} head
 * @return {boolean}
通过快慢指针找到中间节点,然后将链表分成前后两段 将后段链表进行反转 然后比较
奇数个结点,最后slow指向中间的结点;偶数个结点,最后slow指向中间两个结点的后一个
 */
var isPalindrome = function(head) {
    if(head==null||head.next==null){
        return true
    }
    let fast = head
    let slow = head
    let prev
    while(fast&&fast.next){
        prev = slow
        slow = slow.next
        fast = fast.next.next
    }
    //将链表断开
    prev.next = null
    //将后半段链表进行反转
    let tempNode = null
    while(slow){
        let nextNode = slow.next
        slow.next = tempNode
        tempNode = slow
        slow = nextNode
    }
    //进行比较 两个链表  如果原来的链表是奇数个 那么分段之后的链表 后一段会多一个结点
    let head2 = tempNode
    while(head&&head2){
        if(head.val!==head2.val){
            return false
        }
        head = head.next
        head2 = head2.next
    }
    return true
};

方法二:遍历链表,将val保存到数组中,然后使用reverse()反转数组,然后进行比对

注意:reverse()会改变原来的数组,这里使用slice()创建了一个新的数组进行反转

/**
 * @param {ListNode} head
 * @return {boolean}
将链表的值全都放入数组中,然后进行数组的反转  reverse() 会改变原数组
 */
var isPalindrome = function(head) {
    if(head==null||head.next==null){
        return true
    }
    let cur = head
    let res = []
    while(cur!==null){
        res.push(cur.val)
        cur = cur.next
    }
    //reverse() 会改变原数组  于是想着使用formerArr来保存原来的数组 这样是不对的 res:数组和对象是复杂类型,变量中保存的是地址
    // let formerArr = res   这样是不对的 当res变化的时候 formerArr也会变化
    //使用slice()来创建一个新的数组 这样就不会改变原来的数组
    let reverseArr = res.slice().reverse()
    for(let i=0;i<res.length;i++){
        if(res[i]!==reverseArr[i]){
            return false
        }
    }
    return true
};

方法三:同样是将val保存到数组中,这里不反转数组

思路:保存到数组之后,从数组首尾进行比对

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {boolean}
将链表的值全都放入数组中,然后进行数组的反转  reverse() 会改变原数组
 */
var isPalindrome = function(head) {
    if(head==null||head.next==null){
        return true
    }
    let cur = head
    let arr = []
    while(cur!==null){
        arr.push(cur.val)
        cur = cur.next
    }
    let start = 0,end = arr.length - 1
    while(end>=start){
        if(arr[start]!==arr[end]){
            return false
        }
        start++
        end--
    }
    return true

};

9.回文数

var isPalindrome = function(x) {
//转换成字符串
    let str = x.toString()
    let i = 0
    let tempStr = ''
    //进行反转
    while(i<str.length){
        tempStr = str.charAt(i) + tempStr
        i++
    }
    if(tempStr === str){
        return true
    }else{
        return false
    }
};

5.最长回文子串

方法一:中心元素拓展法

var longestPalindrome = function(s) {
   //中心扩展法 直接拼接字符串
   let maxStr = ''
   //下标为i的 都可以作为一次中心元素 向两侧进行拓展
   for(let i=0;i<s.length;i++){
       let left = i-1
       let str = s[i]
       //如果遇到相同的元素,就像将其拼接上  res:相同的元素总是对称的 然后向两侧进行拓展
       while(s[i+1]==s[i]){ //这里不用考虑越界的问题,如果i+1越界了,那么这里就不会相等
           str = str + s[i+1]      //如果遇到相邻的一连串相同的元素,都要将其加上,如果不加上的话,一定比全都有的情况要短
           i++              //因为相同的连续元素都要加上,这里就直接i++了,不用重复进行遍历了 
       }
       //中心元素右侧
       let right = i+1
       while(s[left]==s[right]&&s[left]!==undefined){//要防止left越界  这里right如果越界了,那么等号就不成立了
           str = s[left] + str + s[right]
           left--
           right++
       }
       if(str.length>maxStr.length){
           maxStr = str
       }
   }
   return maxStr
};

中心元素拓展法优化

var longestPalindrome = function(s) {
    //最大长度
   let max = 1
   //字符串开始的位置
   let now = 0
   //下标为i的 都可以作为一次中心元素 向两侧进行拓展
   for(let i=0;i<s.length;i++){
       let left = i-1
       //当前长度
       let curNum = 1
       //如果遇到相同的元素,就像将其拼接上  res:相同的元素总是对称的 然后向两侧进行拓展
       while(s[i+1]==s[i]){ //这里不用考虑越界的问题,如果i+1越界了,那么这里就不会相等
           curNum++     //如果遇到相邻的一连串相同的元素,都要将其加上,如果不加上的话,一定比全都有的情况要短
           i++              //因为相同的连续元素都要加上,这里就直接i++了,不用重复进行遍历了 
       }
       //中心元素右侧
       let right = i+1
       while(s[left]==s[right]&&s[left]!==undefined){//要防止left越界  这里right如果越界了,那么等号就不成立了
           curNum+=2
           left--
           right++
       }
       if(max<curNum){
           max = curNum
           //为啥要加1   因为在向两则进行拓展的时候,left先减一 然后再去判断
           now = left + 1
       }
   }
   return s.slice(now,now+max)
};

方法二:动态规划

var longestPalindrome = function(s) {
    //动态规划  使用一个二维数组来保存 i到j之间的字符串是否是回文字符串
    let len  = s.length
    //创建一个二维数组  如果arr[i][j] = 1 那么i到j之间是回文字符串
    let arr = new Array(len).fill(0).map(item => item = new Array(len).fill(0))
    //记录最大长度
    let max = 0
    //记录最大长度字符串的起始位置
    let maxStart = 0,maxEnd = 0
    let r = 0,l = 0
    for( r = 1;r<len;r++){
        for( l = 0;l<r;l++){
            // r-l<=2 最多有三个元素
            if(s[l]==s[r]&&(r-l<=2 || arr[l+1][r-1]==1)){
                arr[l][r] = 1
                if(max<r-l+1){
                    max = r-l+1
                    maxStart = l
                    maxEnd = r
                }
            }
        }
    }
    return s.slice(maxStart,maxEnd+1)
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值