lintcode 中等题:Palindrome Linked List 回文链表

题目

回文链表

设计一种方式检查一个链表是否为回文链表。

样例

1->2->1 就是一个回文链表。

挑战

O(n)的时间和O(1)的额外空间。

解题

法一:

再定义一个链表,存放链表反转的值,再以此比较两个链表中的值是否相等,时间复杂度O(N),空间复杂度O(N)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    /**
     * @param head a ListNode
     * @return a boolean
     */
    public boolean isPalindrome(ListNode head) {
        // Write your code here
        ArrayList<Integer> list = new ArrayList<Integer>();
        if(head == null || head.next == null)
            return true;
        ListNode p = head;
        ListNode prev = new ListNode(head.val);
        while(p.next != null){
            ListNode tmp = new ListNode(p.next.val);
            tmp.next = prev;
            prev = tmp;
            p = p.next;
        }
        ListNode p1 = head;
        ListNode p2 = prev;
        while(p1!=null){
            if(p1.val != p2.val)
                return false;
            p1 = p1.next;
            p2 = p2.next;
        }
        return true;

    }
}

Java Code

总耗时: 2219 ms

Python下面程序出现内存溢出

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # @param head, a ListNode
    # @return a boolean
    def isPalindrome(self, head):
        # Write your code here
        if head == None or head.next == None:
            return True
        p = head
        prev = ListNode(head.val)
        while p.next!=None:
            tmp = ListNode(p.next.val)
            tmp.next = prev
            prev = tmp
            p = p.next
        p1 = head
        p2 = prev
        del head
        del prev
        while p1!=None:
            if p1.val != p2.val:
                return False
            p1 = p1.next
            p2 = p2.next
        return True 

Python Code

法二:

先找到链表的中间节点,根据中间节点划分成两个链表,对第二个链表反转后在和第一个链表元素以此比较,但是下面的程序,在旋转的过程中空间复杂度好像是O(N/2) = O(N)

在找中间节点时候需要说明下

        ListNode slow = head;
        ListNode fast = head;
        // 找到两个链表的中间节点
        while( fast.next!=null && fast.next.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }

开始时候两个节点都指向第一个节点,以后两个异步的向前走

最后结束的时候

当长度是奇数的时候:slow恰好在中间节点,fast恰好在最后一个节点。slow.next就是下一个链表的头节点。你会发现这两个链表是不一样的长的,但是在比较的时候,只要有一个链表是null的时候就结束比较的,也就是说只与第二个链表有关系的。

当长度是偶数的时候:slow在N/2的下取整处的节点,也就是中间两个节点的前一个,二fast在倒数第二个节点,下面就一样了

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    /**
     * @param head a ListNode
     * @return a boolean
     */
    public boolean isPalindrome(ListNode head) {
        // Write your code here
        if(head == null || head.next == null)
            return true;
        ListNode slow = head;
        ListNode fast = head;
        // 找到两个链表的中间节点
        while( fast.next!=null && fast.next.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode secondHead = slow.next;
        slow.next = null;
        // 后半部分的节点反转
        ListNode p1 = secondHead;
        ListNode revsecondList = new ListNode(p1.val);
        revsecondList.next = null;
        while(p1.next != null){
            ListNode tmp = new ListNode(p1.next.val);
            tmp.next = revsecondList;
            revsecondList = tmp;
            p1 = p1.next;
        }

        // 比较两个链表
        while(head!=null && revsecondList!=null){
            if(head.val != revsecondList.val)
                return false;
            head = head.next;
            revsecondList = revsecondList.next;
        }
        return true;
    }
}

Java Code

总耗时: 2229 ms

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # @param head, a ListNode
    # @return a boolean
    def isPalindrome(self, head):
        # Write your code here
        if head == None or head.next == None:
            return True
        slow = head
        fast = head
        while fast.next != None and fast.next.next != None:
            fast = fast.next.next
            slow = slow.next
        secondHead = slow.next
        slow.next = None
        p = secondHead
        rev = ListNode(p.val) 

        while p.next!=None:
            tmp = ListNode(p.next.val)
            tmp.next = rev
            rev = tmp
            p = p.next

        while rev!=None and head!=None:
            if rev.val != head.val:
                return False
            rev = rev.next
            head = head.next
        return True 

Python Code

总耗时: 528 ms

在旋转链表的时候有重新定义了节点,如何只是修改节点而实现翻转,下面利用递归的思想翻转链表,但是在测试到97%的数据的时候运行时间超时。

    public ListNode reverse(ListNode head){
        if(head == null || head.next == null)
            return head;
        ListNode second = head.next;
        head.next = null;
        ListNode res = reverse(second);
        second.next = head;
        return res;
    }

Java Code

下面是定义两个指针,第一个指向头节点,第二个指向头节点后一个节点

p1 = head
p2 = p1.next
while(p1!= null && p2!= null){
ListNode tmp = p2.next;
p2.next = p1;
p1 = p2;
p2 = tmp;
}

操作如下图所示

这里可以最后A还指向B的,可以在初始定义中增加

p1 .next = null

这样每次都是在p1节点之前增加一个节点的

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    /**
     * @param head a ListNode
     * @return a boolean
     */
    public boolean isPalindrome(ListNode head) {
        // Write your code here
        if(head == null || head.next == null)
            return true;
        ListNode slow = head;
        ListNode fast = head;
        // 找到两个链表的中间节点
        while( fast.next!=null && fast.next.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode secondHead = slow.next;
        slow.next = null;
        // 后半部分的节点反转
        ListNode p1 = secondHead;
        ListNode p2 = p1.next;
        p1.next = null;

        while(p1!= null && p2!= null){
            ListNode tmp = p2.next;
            p2.next = p1;
            p1 = p2;
            p2 = tmp;
        }
        secondHead.next = null;
        revsecondList = p1;
        // 比较两个链表
        while(head!=null && revsecondList!=null){
            if(head.val != revsecondList.val)
                return false;
            head = head.next;
            revsecondList = revsecondList.next;
        }
        return true;
    }
}

Java Code

总耗时: 2192 ms

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # @param head, a ListNode
    # @return a boolean
    def isPalindrome(self, head):
        # Write your code here
        if head == None or head.next == None:
            return True
        fast = head
        slow = head
        while fast.next!= None and fast.next.next!=None:
            fast =fast.next.next
            slow = slow.next
        secondhead = slow.next
        slow.next = None

        p1 = secondhead
        p2 = p1.next
        p1.next = None
        while p1!=None and p2!=None:
            tmp = p2.next
            p2.next = p1
            p1 = p2
            p2 = tmp
        rev = p1
        while rev!=None and head!=None:
            if rev.val!=head.val:
                return False
            rev = rev.next
            head = head.next
        return True 

Python Code

总耗时: 516 ms

时间: 2024-12-05 08:40:39

lintcode 中等题:Palindrome Linked List 回文链表的相关文章

[CareerCup] 2.7 Palindrome Linked List 回文链表

2.7 Implement a function to check if a linked list is a palindrome. LeetCode上的原题,参见我之前的博客Palindrome Linked List 回文链表.

LeetCode Palindrome Linked List (回文链表)

题意:给个单链表,判断是否为回文. 思路:有点BT,处理不好都是死循环.一般思路是,二分查找中心点,根据奇偶个元素,反置前半部分,再判断是否回文,再恢复前半部分. 步骤: (1)在二分查找中心点时判断顺便反置前半部分链表. (2)对奇偶数处理好剩下的工作.这是重点 (3)两个指针来判断是否回文. (4)将前半段恢复起来,比较简单,有个head作为界限标志呢. 1 /** 2 * Definition for singly-linked list. 3 * struct ListNode { 4

如何判断一个单向链表是否为回文链表(Palindrome Linked List)

题目:给定一个单向链表,判断它是不是回文链表(即从前往后读和从后往前读是一样的).原题见下图,还要求了O(n)的时间复杂度O(1)的空间复杂度. 我的思考: 1,一看到这个题目,大脑马上想到的解决方案就是数组.遍历链表,用数组把数据存下来,然后再进行一次遍历,同时用数组反向地与之比较,这样就可以判断是否回文.这个方法时间复杂度是O(n),达到了要求,然而空间复杂度显然不满足要求.所以,开数组这一类的方法显然不是最佳的. 2,既然要满足O(1)的空间复杂度,我就想到了用一个变量来存储这些数据,恰好

Palindrome Number (回文数)

回文数是指这样的数字:正读和倒读都是一样的.如:595,2332都是回文数,234不是回文数. 注意:负数不是回文数 Determine whether an integer is a palindrome. Do this without extra space. Some hints: Could negative integers be palindromes? (ie, -1) If you are thinking of converting the integer to string

leetcode题解:Valid Palindrome(判断回文)

题目: Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases. For example,"A man, a plan, a canal: Panama" is a palindrome."race a car" is not a palindrome. Note:Have you consider tha

【leetcode 简单】 第六十七题 回文链表

请判断一个链表是否为回文链表. 示例 1: 输入: 1->2 输出: false 示例 2: 输入: 1->2->2->1 输出: true 进阶: 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题? # Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def r

LeetCode 234——回文链表

1. 题目 请判断一个链表是否为回文链表. 示例 1: 输入: 1->2 输出: false 示例 2: 输入: 1->2->2->1 输出: true 进阶: 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题? 2. 思路 此题可以看做是反转链表 和 链表中间结点 的结合. 定义快慢两个指针,寻找中间结点,同时在慢指针移动的过程中反转前半部分子链表.当找到中间结点时,再分别向前向后比较前后两个子链表的每一个结点值是否相同. 偶数结点情况如下 此时,我们分别得到了以

Leetcode 234. 回文链表(进阶)

题目描述: 请判断一个链表是否为回文链表. 示例 1: 输入: 1->2 输出: false 示例 2: 输入: 1->2->2->1 输出: true 进阶: 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题? 解法一:(空间复杂度O(n)) 遍历一遍链表压栈,借助栈把链表倒序,然后依次比较"原链表元素"和"新栈中元素",如果都相等则返回true,否则返回false. 这样简单粗暴,代码的主体包含在解法二中了,这里不列出了.

领扣(LeetCode)回文链表 个人题解

请判断一个链表是否为回文链表. 示例 1: 输入: 1->2 输出: false 示例 2: 输入: 1->2->2->1 输出: true 进阶:你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题? 一个最暴力的做法,遍历一次,内容保存在数组内,然后判断是否回文. 遇到一个比较严重的问题需要记录一下,使用Vector类时,设定的类型为Integer,必须使用Equals函数来判断两数是否相等,使用==则不行.奇怪的是,只有部分判断是错误的. 查阅百度,发现了问题所在: