[LeetCode-234] Palindrome Linked List(回文链表、链表中间节点查找)

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

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

【分析】

找到链表中点,拆分后,逆转后半个链表,然后两个链表同时顺序遍历一次。

不过唯一需要注意的是,当链表长度为奇数,我们需要先将链表中点往下移动一个节点后在反转半个链表

比如{1->2->3->2->1} 我们找到链表中点3之后需要向下移动一个节点{1->2->3}只需要比较1->2 这两个节点是否相等

时间复杂度O(n),空间复杂度O(1)

代码如下:

struct LinkNodeMid {
	struct ListNode *LastNode;
	struct ListNode *NodeMid;
};
/*无头结点*/
struct ListNode* reverseList(struct ListNode* head) 
{
    if((head == NULL) || (head->next==NULL))  //链表为空,或只有一个结点(无需反转),直接返回
        return head;

    struct ListNode *pre = NULL;//前一个
    struct ListNode *cur = NULL;//当前
    struct ListNode *ne = NULL;//后一个

    pre = head;         //将前面几个节点的地址依次保存在新定义的结构体指针
    cur = head ->next;

    while(cur)
    {
        ne = cur->next;  //如果当前节点不为空,则将其指针域赋给ne指针
        cur->next = pre; //直接将两个指针的指向反转
        pre = cur;       //将当前节点赋给pre,将三个指针在链表中的位子都往后移一位
        cur = ne;     
    }
    head->next = NULL;//将原来的第一个节点的指针域赋为空,作为尾节点
    head = pre;      //将原来的尾节点变成新链表的第一个节点
    return head;
}

struct LinkNodeMid* getLinkNodeMid(struct ListNode* head)
{
	/*at least two nodes*/
	struct ListNode* slow = head;
	struct ListNode* fast = head;
	struct LinkNodeMid* LinkNodeMidinfo = (struct LinkNodeMid*)malloc(sizeof(struct LinkNodeMid));
   /*Fast Linknode move double step one time,
   	slow Linknode move one step,
   	then the slow is the mid head*/
   while(fast != NULL && fast->next != NULL) {		
		slow = slow->next;	
		fast = fast->next->next;/*even is NULL,then end the cycle*/
   }
   
   LinkNodeMidinfo->LastNode = fast;
   LinkNodeMidinfo->NodeMid = slow;

   return LinkNodeMidinfo;
}

bool isPalindrome(struct ListNode* head)
{
    if(!head||!head->next)
		return true;
	struct ListNode* phead = head;
	struct LinkNodeMid* LinkNodeMidinfo= getLinkNodeMid(phead);
	struct ListNode* pReverseListhead = NULL;
	
	/*if LastNode is NULL,then the length LinkNode is odd,otherwise is even*/
	if(LinkNodeMidinfo->LastNode) {
		pReverseListhead = reverseList(LinkNodeMidinfo->NodeMid->next);
	}
	else {
		pReverseListhead = reverseList(LinkNodeMidinfo->NodeMid);
	}
	
	while(phead && pReverseListhead) {
		if(phead->val != pReverseListhead->val) {
			free(LinkNodeMidinfo);
			return false;
		}
		phead = phead->next;
		pReverseListhead = pReverseListhead->next;
	}
	free(LinkNodeMidinfo);
	return true;	
}

完整的代码如下:

// LeetCode234-Palindrome Linked List.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
/**
 * Definition for singly-linked list.
 **/
struct ListNode {
     int val;
     struct ListNode *next;
};
/*1.Get LinkNodeMid by NodeMid;
2.LastNode is to distinguish the length LinkNode is odd or even
if LastNode is NULL,then the length LinkNode is odd,otherwise is even*/
struct LinkNodeMid {
	struct ListNode *LastNode;
	struct ListNode *NodeMid;
};
struct ListNode* CreatLink(int aData[],int len)
 {
     if(!aData)
         return NULL;
     struct ListNode *head = NULL;
     struct ListNode *p = NULL;
     struct ListNode *Link= NULL;
     /*第一个节点*/
     head = (struct ListNode *)malloc(sizeof(struct ListNode));
     head->val = aData[0];
     head->next = NULL;
    // aData ++;
     Link = head; /*保存头结点*/
     int i = 1;

     while(i < len) {
         p = (struct ListNode *)malloc(sizeof(struct ListNode));
         p->val = aData[i];
         head->next = p;
         head = p;
         i ++;
     }

     head->next = NULL;
     return Link;
 }

 void printLink(struct ListNode *head)
 {
     while(head) {
         printf("%d",head->val);
         head = head->next;
     }
     printf("\n");
 }

/*无头结点*/
struct ListNode* reverseList(struct ListNode* head) 
{
    if((head == NULL) || (head->next==NULL))  //链表为空,或只有一个结点(无需反转),直接返回
        return head;

    struct ListNode *pre = NULL;//前一个
    struct ListNode *cur = NULL;//当前
    struct ListNode *ne = NULL;//后一个

    pre = head;         //将前面几个节点的地址依次保存在新定义的结构体指针
    cur = head ->next;

    while(cur)
    {
        ne = cur->next;  //如果当前节点不为空,则将其指针域赋给ne指针
        cur->next = pre; //直接将两个指针的指向反转
        pre = cur;       //将当前节点赋给pre,将三个指针在链表中的位子都往后移一位
        cur = ne;     
    }
    head->next = NULL;//将原来的第一个节点的指针域赋为空,作为尾节点
    head = pre;      //将原来的尾节点变成新链表的第一个节点
    return head;
}

struct LinkNodeMid* getLinkNodeMid(struct ListNode* head)
{
	/*at least two nodes*/
	struct ListNode* slow = head;
	struct ListNode* fast = head;
	struct LinkNodeMid* LinkNodeMidinfo = (struct LinkNodeMid*)malloc(sizeof(struct LinkNodeMid));
   /*Fast Linknode move double step one time,
   	slow Linknode move one step,
   	then the slow is the mid head*/
   while(fast != NULL && fast->next != NULL) {		
		slow = slow->next;	
		fast = fast->next->next;/*even is NULL,then end the cycle*/
   }
   
   LinkNodeMidinfo->LastNode = fast;
   LinkNodeMidinfo->NodeMid = slow;

   return LinkNodeMidinfo;
}

bool isPalindrome(struct ListNode* head)
{
    if(!head||!head->next)
		return false;
	struct ListNode* phead = head;
	struct LinkNodeMid* LinkNodeMidinfo= getLinkNodeMid(phead);
	struct ListNode* pReverseListhead = NULL;
	
	/*if LastNode is NULL,then the length LinkNode is odd,otherwise is even*/
	if(LinkNodeMidinfo->LastNode) {
		pReverseListhead = reverseList(LinkNodeMidinfo->NodeMid->next);
	}
	else {
		pReverseListhead = reverseList(LinkNodeMidinfo->NodeMid);
	}
	
	while(phead && pReverseListhead) {
		if(phead->val != pReverseListhead->val) {
			free(LinkNodeMidinfo);
			return false;
		}
		phead = phead->next;
		pReverseListhead = pReverseListhead->next;
	}
	free(LinkNodeMidinfo);
	return true;	
}

int _tmain(int argc, _TCHAR* argv[])
{

	int a[] = {1,1,2,1,1};
    struct ListNode *head1 = NULL;
    head1 = CreatLink(a,sizeof(a)/sizeof(int));
	//printLink(head1);
	printf("[%d] %d\n",__LINE__,isPalindrome(head1));
	free(head1);
	getchar();
	return 0;
}



你可能感兴趣的:(LeetCode)