leetcode面试题 02.06. 回文链表,解题心路

leetcode面试题 02.06. 回文链表,解题心路

1、题目描述

编写一个函数,检查输入的链表是否是回文的。如图:

试题链接:https://leetcode-cn.com/problems/palindrome-linked-list-lcci/

2、java语言题解一

看到该题,首先想打到的就是使用自己最拿手的语言java来做。首先,我们先来观查题目所给链表的结构:

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

由于题目中要求判断一个链表是否回文,因此很自然的一个想法就是,将链表变量,取出其中的值,放在一个有序的容器中。在java中很自然的就想到了list集合,于是就有了下述的解法:

public static boolean isPalindrome(ListNode head) {
    List list = new ArrayList();
    //定义一个辅助指针,用来遍历链表
    ListNode pCurrent = head;
    //当链表不为null时,就一直循环
    while (pCurrent != null) {
        //将该数保存到数组中
        list.add(pCurrent.val);
        pCurrent = pCurrent.next;
    }
    //遍历集合,看首尾是否相等
    for(int i = 0;i < list.size() / 2;i++) {
        if(!list.get(i).equals(list.get(list.size() - i - 1))) {
            return false;
        }
    }
    return true;
}

算法效果:

可以看出,该算法在java的提交记录中,时间稍微较慢,当时所需要的内存确实最少的。然而,计算机程序比较关心的是算法的执行效率,因此该算法还得进行改进。

3、java语言题解二

由于上述的算法的执行时间太长,猜想是不是因为使用了List集合而导致的。但是,如果不适用集合,我们的先获取到该链表的长度,然后定义一个大小刚刚适合的数组。代码如下:

public static boolean isPalindrome(ListNode head) {
    //定义一个辅助指针,用来遍历链表
    ListNode pCurrent = head;
    //当链表不为null时,就一直循环
    int count = 0;
    while (pCurrent != null) {
        //计数
        count++;
        pCurrent = pCurrent.next;
    }
    //再来一论,装进数组
    pCurrent = head;
    int[] arr = new int[count];
    for(int i = 0;i < count;i++) {
        arr[i] = pCurrent.val;
        pCurrent = pCurrent.next;
    }
    //遍历集合,看首尾是否相等
    for(int i = 0;i < count / 2;i++) {
        if(arr[i] != arr[count - i - 1]) {
            return false;
        }
    }
    return true;
}

算法效果:

可以看出,用数组代替集合,增加一次循环后的效率得到大幅度的提升。

4、C语言题解一

奈何,博主目前还是一个本科大学生,在数据结构与算法这门课上垂死挣扎,而考试只允许用C来作答,因此,只有用C语言重写上述的java算法。

  1. 先来看看在C语言中,题目给出的链表的结构题类型
struct ListNode {
    int val;
    struct ListNode *next;
};

接下来,用C语言来实现上述的java题解二:

bool isPalindrome(struct ListNode* head){
    //定义一个辅助指针,用来遍历链表
    struct ListNode* pCurrent = head;
    //当链表不为null时,就一直循环
    int count = 0;
    while (pCurrent != NULL) {
        //计数
        count++;
        pCurrent = pCurrent->next;
    }
    if(count == 0)
        return true;
    //再来一论,装进数组
    pCurrent = head;
    int arr[count];
    for(int i = 0;i < count;i++) {
        arr[i] = pCurrent->val;
        pCurrent = pCurrent->next;
    }
    //遍历集合,看首尾是否相等
    for(int i = 0;i < count / 2;i++) {
        if(arr[i] != arr[count - i - 1]) {
            return false;
        }
    }
    return true;
}

算法效果:

由执行用时可以看出,在C语言的解法中,该算法并不是最优解。

除此之外,还有另外一种思路,就是将链表拆分成两部分,然后使得一部分反转,后遍历两个链表,观察是否相等。但是,该方法经过博主测试后,发现其效率还不如上述解法高效,因此不在叙述,后续如果有新的更高效解法在来叙述。

posted @ 2020-02-27 18:27  孤傲的咸鱼  阅读(324)  评论(0编辑  收藏  举报