题解 | #牛群编号的回文顺序II# Java

牛群编号的回文顺序II

https://www.nowcoder.com/practice/e887280579bb4d91934378ea359f632e

基本思路是将链表转换为字符串,并使用动态规划的方法来寻找最长回文子链表。

首先,判断链表是否为空或只有一个节点,如果是的话,则直接返回null。

然后,将链表中的节点值依次添加到StringBuilder中,以形成一个字符串表示整个链表。

接下来,初始化一些变量,包括长度(len)为字符串长度、最大回文子链表长度(maxLen)初始化为1,和回文子链表起始位置(begin)初始化为0。

接着,创建一个布尔型的二维数组dp,其中dp[i][j]表示字符串s的第i个字符到第j个字符是否为回文串。将所有长度为1的子串都初始化为回文串。

将字符串转换为字符数组charArray,为后续判断字符是否相等做准备。

开始进行动态规划的递推过程。

首先,外层循环枚举子串长度(l从2到len)。

然后,内层循环枚举左边界(i从0到len)。

确定右边界(j = i + l - 1),并检查是否越界,若越界则退出内层循环。

如果charArray[i]与charArray[j]不相等,则dp[i][j]为false;否则,如果子串长度小于等于3,则直接为回文串,即dp[i][j]为true;如果子串长度大于3,则需要根据内圈dp[i+1][j-1]的值来判断是否为回文串。

如果dp[i][j]为true,并且子串长度大于maxLen,则更新maxLen和begin。

最后,根据begin和maxLen找到链表中的最大回文子链表的起始节点和结束节点(tail),然后将结束节点的next指针置为null,以断开后续节点。

最后,返回最大回文子链表的起始节点。

需要注意的是,如果整个链表都是回文的,即begin为0且maxLen等于sb.length(),则返回null。

public class Solution {

    public ListNode maxPalindrome (ListNode head) {
        if (head == null || head.next == null) return null;

        StringBuilder sb = new StringBuilder();
        ListNode cur = head;
        while (cur != null) {
            sb.append(cur.val);
            cur = cur.next;
        }
        // 求这个最大的连续回文子链表
        int len = sb.toString().length();
        int maxLen = 1;
        int begin = 0;
        // dp[i][j]表示s[i,j]是否是回文串
        boolean[][] dp = new boolean[len][len];
        // 初始化:所有长度为1的子串都是回文串
        for (int i = 0; i < len; i++) {
            dp[i][i] = true;
        }
        char[] charArray = sb.toString().toCharArray();
        // 递推开始
        // 先枚举子串长度
        for (int l = 2; l <= len; l++) {
            // 枚举左边界
            for (int i = 0; i < len; i++) {
                // 有子串长度+左边界 -> 右边界: i+l-1
                int j = i + l - 1;
                // 如果右边界越界,结束内层循环
                if (j >= len) break;

                if (charArray[i] != charArray[j]) {
                    dp[i][j] = false;
                } else {
                    if (j - i < 3) dp[i][j] = true; //长度为2 3直接是
                    else dp[i][j] = dp[i + 1][j - 1]; // 等于内圈是否满足
                }
                // 只要dp[i][j]==true 就表示字串s[i,j]是回文子串,记录此时回文长度和起始位置
                if (dp[i][j] && j - i + 1 > maxLen) {
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }

        if (begin == 0 && maxLen == sb.length()) return null; //整个串都是回文的

        while (begin-- > 0) {
            head = head.next;
        }
        ListNode tail = head;
        for (int p = 0; p < maxLen - 1; p++) {
            tail = tail.next;
        }
        tail.next = null; // 断掉后面
        return head;
    }
}

算法题刷刷刷 文章被收录于专栏

数组、链表、栈、队列、堆、树、图等。 查找和排序:二分查找、线性查找、快速排序、归并排序、堆排序等。 动态规划:背包问题、最长公共子序列、最短路径 贪心算法:活动选择、霍夫曼编码 图:深度优先搜索、广度优先搜索、拓扑排序、最短路径算法(如 Dijkstra、Floyd-Warshall) 字符串操作:KMP 算法、正则表达式匹配 回溯算法:八皇后问题、0-1 背包问题 分治算法:归并排序、快速排序

全部评论

相关推荐

鼗:眼睛打码有点那啥的味道
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务