LeetCode 234. Palindrome Linked List(回文链表) -- c语言

234. Palindrome Linked List

Given a singly linked list, determine if it is a palindrome.

Example 1:

Input: 1->2
Output: false

Example 2:

Input: 1->2->2->1
Output: true

Follow up:
Could you do it in O(n) time and O(1) space?

解题思路:

方法一:

首先设置快慢指针fast,slow找出中点mid,分为前半部分和后半部分;再将后半部分反转,反转后前后部分同时顺序遍历并比较确定是否是回文链表。Note:链表奇数时,中心点在后半部分;链表偶数时中心点在前半部分尾部

/*
执行用时 : 24 ms, 在Palindrome Linked List的C提交中击败了94.38% 的用户
内存消耗 : 11.1 MB, 在Palindrome Linked List的C提交中击败了40.26% 的用户
*/

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


bool isPalindrome(struct ListNode* head){
    //特殊情况先行讨论
    if(!head || !head->next){
        return true;
    }
    
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    struct ListNode* mid = head;

    //找中心点,此时slow指向后半部分第一个结点,mid指向前半部分最后一个结点
    while(fast != NULL && fast->next != NULL){
        mid = slow;
        fast = fast->next->next;
        slow = slow->next;
    }
    
    //反转后半部分
    struct ListNode* q = NULL;//保存当前处理结点的后继结点,防止丢失后继结点
    fast = slow->next;
    while(fast != NULL){
        q = fast->next;
        fast->next = slow;
        slow = fast;
        fast = q;
    }

    //前后部分同时遍历比较是否是回文
    fast = head;
    while(fast != mid->next){//条件也可以先置mid->next = NULL,再判定while(fast!=NULL)
        if(fast->val != slow->val){
            return false;
        }
        fast = fast->next;
        slow = slow->next;
    }
    
    return true;

}

微调:

/*
执行用时 : 16 ms, 在Palindrome Linked List的C提交中击败了99.78% 的用户
内存消耗 : 11 MB, 在Palindrome Linked List的C提交中击败了48.92% 的用户
*/

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


bool isPalindrome(struct ListNode* head){
    
    if(!head || !head->next){
        return true;
    }
    
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    struct ListNode* mid = head;
    
    while(fast != NULL && fast->next != NULL){
        mid = slow;
        fast = fast->next->next;
        slow = slow->next;
    }
    //将前半部分与后半部分断开
    mid->next = NULL;
    
    
    fast = slow->next;
    while(fast != NULL){
        mid = fast->next;//重复利用fast和mid指针,节约空间
        fast->next = slow;
        slow = fast;
        fast = mid;
    }
    
    fast = head;
    //由于前面已经设置前半部分最后为NULL,所以此处可以直接判定空
    while(fast != NULL){
        if(fast->val != slow->val){
            return false;
        }
        fast = fast->next;
        slow = slow->next;
    }
    
    return true;

}

 

方法二:

定义一个数组A[],将链表值赋值给数组,然后判定数组是否是回文的,即判定链表是否是回文的

/*
执行用时 : 16 ms, 在Palindrome Linked List的C提交中击败了99.78% 的用户
内存消耗 : 11.2 MB, 在Palindrome Linked List的C提交中击败了34.63% 的用户
*/

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

bool isPalindrome(struct ListNode* head){
    struct ListNode* p = head;
    int n = 1,k = 1;
    //统计链表个数
    while(p!=NULL){
        n++;p=p->next;
    }
    
    //将链表结点值赋值到数组
    int A[n];
    p = head;
    while(p!=NULL){
        
        A[k++] = p->val;
        p=p->next;
    }
    
    //首尾同时遍历数组A[]确定是否是回文
    int i=1,j=n-1;
    while(i<j){
        if(A[i]!=A[j])return false;
        i++;j--;
    }
    
    return true;
    
}

 

方法三: 

将链表看成是每个结点代表一位的数,通过遍历链表把顺序和逆序的数值计算出来,然后再比较两数值是否相等

/*
执行用时 : 20 ms, 在Palindrome Linked List的C提交中击败了98.43% 的用户
内存消耗 : 10.8 MB, 在Palindrome Linked List的C提交中击败了90.48% 的用户
*/

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

bool isPalindrome(struct ListNode* head){
    //特殊情况
    if(head == NULL || head->next == NULL){
        return true;
    }
    
    //初始化统计第一个结点值
    struct ListNode* p = head->next;
    float ordSum = head->val;//统计整个链表顺序时的组合的数值
    float revSum = head->val;//统计整个链表逆序时的组合的数值
    float i = 1;
    
    //统计剩下结点值
    while(p){
        
        ordSum = ordSum*10 + p->val;
        i = i*10;
        revSum = revSum + p->val *i;
        p = p->next;
    }
    
    if(ordSum == revSum){
        return true;
    }
    else{
        return false;
    }
}

后记:

  1. 方法一还可以通过反转前半部分来实现。此时前半部分的反转和中点的寻找可以如上分开求,也可以在一个循环内边反转边找中点。
  2. 方法二中如果#define MaxSize INT_MAX  int A[MaxSize];会报错,所以上面添加了一个统计链表个数的实现。如果你有更好的方法希望可以评论告知,将不胜感激
  3. 此题还可以用栈的方法,但不知道leetcode上c语言栈的用法,故没有贴出。感兴趣的你也可以自己定义栈或者寻找调用leetcode系统栈的方法
  4. 方法三中ordSum定义为int类型时
    Line 24: Char 24: runtime error: signed integer overflow: -299381302 * 10 cannot be represented in type ‘int’ (solution.c)
    最后执行的输入:[-31900,22571,-31634,19735,13748,16612,-28299,-16628,9614,-14444,-14444,9614,-16628,-31900,16612,13748,19735,-31634,22571,-28299]
    方法三中ordSum定义为 long int类型时
    Line 24: Char 24: runtime error: signed integer overflow: -2993799396147191188 * 10 cannot be represented in type ‘long int’ (solution.c)

贴出一份别人用栈实现的LeetCode提交范例:
 

//执行时间:60ms
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct my_stack* Stack;
struct my_stack{
     int val;
     struct my_stack *next;
};

Stack createStack(){
    Stack head;
    head = (struct my_stack *)malloc(sizeof(struct my_stack));
    head->next = NULL;
    return head;
}

int isEmpty(Stack s){
    return (s->next == NULL);
}

void push(int val,Stack s){
    Stack cell;
    cell = (struct my_stack *)malloc(sizeof(struct my_stack));
    cell->val = val;
    cell->next = s->next;
    s->next = cell;
}

int pop(Stack s){
    Stack topcell;
    int element;
    if(isEmpty(s))
        return NULL;
    else{
        topcell = s->next;
        s->next = topcell->next;
        element = topcell->val;
        free(topcell);     
    }   
    return element;
}

bool isPalindrome(struct ListNode* head) {
    if(head == NULL)
        return true;
    
    Stack h = createStack();     
    struct ListNode* l = head;
    while(l != NULL){
        push(l->val,h);
        l = l->next;
    }
     
    while(head != NULL){
        if( pop(h) == head->val )            
            head = head->next;
        else
            return false;
    }    
            return true;        
}

此范例仅供参考。

点赞