【leetcode】回文字符串系列

本文详细解析了多种回文串相关算法,包括寻找最长回文子串、计算最长回文子序列长度、构造最短回文串等,并提供了具体代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

5. Longest Palindromic Substring

题目:找到一个字符串中最长的回文子串

思路:遍历字符串,看以下两种情况得到的子串是不是回文

1)?+目前最长子字符串长度的字符串+当前字符——是回文则最长子字符串长度+2
2)目前最长子字符串长度的字符串+当前字符——是回文则最长子字符串长度+1

判断是否回文需要注意start和end是否在字符串长度外

public class Solution {
    public String longestPalindrome(String s) {
        String ret = new String();
        int current = 0;
        for(int i = 0; i < s.length(); i++){
            if(isPalindrome(s,i-current-1,i)){
                ret = s.substring(i-current-1,i+1);
                current = current + 2;
            }
            else if(isPalindrome(s,i-current,i)){
                ret = s.substring(i-current,i+1);
                current ++;
            }
        }
        return ret;
    }
    public boolean isPalindrome(String s,int start,int end){
        if(start <  0 || end < 0 || start > s.length()-1 || end > s.length()-1) return false;
        while(start < end){
            if(s.charAt(start++) != s.charAt(end--)){
                return false;
            }
        }
        return true;
    }
}


516. Longest Palindromic Subsequence

题目:找到最长回文子串的长度(不连续)

思路:动态规划——建立二维动态规划数组dp,分别存i到j子串的最长回文长度。对角线dp[i][i]均为1,对角线坐下角矩阵均为0,右上角矩阵从下到上慢慢扩散,最后计算出dp[0][s.length()-1]为输出结果。

public class Solution {
    public int longestPalindromeSubseq(String s) {
        int[][] dp =new int[s.length()][s.length()];
        for(int i = s.length() - 1; i >= 0; i--){
            dp[i][i] = 1;
            for(int j = i+1; j < s.length(); j++){
                if(s.charAt(i) == s.charAt(j)){
                    dp[i][j] = dp[i+1][j-1] + 2;
                }
                else{
                    dp[i][j] = Math.max(dp[i+1][j], dp[i][j-1]);
                }
            }
        }
        return dp[0][s.length()-1];
    }
}

214. Shortest Palindrome

题目:在输入字符串前加入最少字符,使其成为一个回文串。

思路:暴力解法——从后往前看子串是否为回文串,是跳出将后面子串反序补到前面,实现没有问题,但是时间复杂度太高。

public class Solution {
    public String shortestPalindrome(String s) {
        int max = 0;
        for(int i = s.length() - 1; i >= 0; i--){
            if(isPalindrome(s.substring(0,i+1))){
                max = i+1;
                break;
            }
        }
        if(max == s.length()) return s;
        StringBuffer sb = new StringBuffer(s.substring(max, s.length()));
        return sb.reverse().toString()+s;
    }
    public boolean isPalindrome(String s){
        if(s.length() == 0) return false;
        int i = 0, j = s.length() -1;
        while(i<j){
            if(s.charAt(i) != s.charAt(j)) return false;
            i++;
            j--;
        }
        return true;
    }
}

KMP算法——没看懂,以后再补充

336. Palindrome Pairs

题目:



9. Palindrome Number

题目:判断一个整数是否为回文,不允许使用额外空间

思路:开始的想法是把整数的每一位打出来,再按位判断是否是回文,但是这样不满足不适用额外空间的要求。参考了别人的解法,这里记录一种比较巧妙的。将整数从个位开始的每一位拿出来,组成一个新的整数,相当于反转。但是当反转整数大于等于原整数的时候跳出循环,这样巧妙的避免了溢出的问题,也减少了运算量。(不过溢出的问题也可以通过long类型来解决)。另外需要注意的一点是,负数不是回文?个位是零的除了零以外都不是回文,因为输入整数第一位必不为零。

public class Solution {
    public boolean isPalindrome(int x) {
        if((x < 0)||(x != 0 && x%10==0)) return false;
        int rev = 0;
        while(x > rev){
            rev = rev*10 + x%10;
            x = x/10;
        }
        return (x == rev)||(x == rev/10);
    }
}


234. Palindrome Linked List

题目:判断一个单向链表是不是回文,要求O(n)时间复杂度和O(1)空间复杂度

思路:Two Pointers——分为三步,第一,找到链表的中间节点,第二,反转后半部分链表,第三,比较前半部分链表和反转后的后半部分链表是否回文。这里在找中间节点的时候用到了快慢指针,遍历一次即可,以前喜欢先算出链表长度,再除2得到中间节点,这个毛病要改掉。

反转链表的过程想复杂了,简单过程如下:

对于1 -> 2,新建pre节点,取null

(1)1 -> 2

    |    |

head节点 next节点

(2)pre <- 1 2

(3)pre <- 1 2

    | |

pre节点  head节点

head为空时跳出循环。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public boolean isPalindrome(ListNode head) {
        if (head == null || head.next == null) return true;
        if(head.next.next == null) return (head.val == head.next.val);
        ListNode fast = head, slow = head;
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        if(fast != null){
            slow = slow.next;
        }
        ListNode pre = null;
        while(slow != null){
            ListNode next = slow.next;
            slow.next = pre;
            pre = slow;
            slow = next;
        }
        slow = pre;
        fast = head;
        while(slow != null){
            if(fast.val != slow.val) return false;
            fast = fast.next;
            slow = slow.next;
        }
        return true;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值