判断一个链表是否是回文结构

判断一个链表是否是回文结构

判断一个链表是否是回文结构

【题目】给定一个单链表的头结点,请判断该链表是否为回文结构

【要求】如果链表长度为N,时间复杂度要求为O(N),额外空间复杂度为O(1)

【示例】1->2->2->1 true ;1->2->1 true ;1->2->3 false

【解题思路】

    • 把链表的全部内容依次放入栈中,再依次弹出栈中元素,并与链表依次进行比较,如果都相等,那么为回文结构,否则不是
    • 时间复杂度:O(N)
    • 空间复杂度:O(N)
  • 快慢指针 + 栈
    • 快指针一次走两步,慢指针一次走一步,当快指针走到结尾时,慢指针走到一半,然后把慢指针后面的部分,放到栈中
    • 时间复杂度:O(N)
    • 空间复杂度:O(N/2)
  • 有限个指针
    • 改变链表右侧区域,使整个右半区域反转,最后指向中间结点;利用指针分别从两端移动,每移动一次比较两值是否一样。最后把链表恢复成原来的样子
    • 空间复杂度O(1)

栈实现

bool isPalindrome1(Node* head){
	Node *p = head->next;
    stack<int> sta;
    while(p){//第一个循环用来把链表数据存入栈中
    	sta.push(p->data);
        p = p->next;
    }
    p = head->next;
    while(p){//第二个循环时为了对比链表数据与栈弹出的数据
    	if(p->data != sta.top())
        	return false;
        sta.pop();
        p = p->next;
    }
    return true;
}

栈+快慢指针

空间复杂度:O(N/2)

bool isPalindrome2(Node* head){
	if(head == NULL || head->next == NULL)
		return true;
	Node* right = head->next;
	Node* cur = head;
	while(cur->next != NULL && cur->next->next != NULL){
	//cout << "right->data:" << right->data << endl;
	//cout << "cur->data:" << cur->data << endl;
		right = right->next;
	cur = cur->next->next;
	}
	
	stack<Node*> sta;
	while(right != NULL){//把中点以后的部分放入栈中
		sta.push(right);
		//cout << "放入栈中的数据为:" << right->data << endl;
		//cout << sta.top()->data << endl;
		right = right->next;
	}

	while(!sta.empty()){
		//cout << sta.top()->data << endl;
		if(head->next->data != sta.top()->data){
			return false;
		}
		head = head->next;
		sta.pop();
	}
	return true;
}

有限个变量

bool isPalindrome3(Node* head){
    if(head == NULL || head->next == NULL)
        return true;
    Node* n1 = head;
    Node* n2 = head;
    //find the mid
    while(n2->next != NULL && n2->next->next != NULL){//查找中间结点
        cout << "n1->data : " << n1->data << endl;
        cout << "n2->data : " << n2->data << endl;
        n1 = n1->next;//n1指向中部
        n2 = n2->next->next;//n2指向尾部
    }
    n2 = n1->next;//n2 right  part first node
    n1->next = NULL;
    Node* n3 = NULL;
    while(n2 != NULL){//右半区反转
        n3 = n2->next;//n3 save next node
        n2->next = n1;//下一个反转结点
        n1 = n2;//n1 move
        n2 = n3;//n2 move
    }
    n3 = n1;//n3 save the last node
    n2 = head->next;//left first node
    bool res = true;
    while(n1 != NULL && n2 != NULL){
        if(n1->data != n2->data){
            res = false;
            break;
        }
        n1 = n1->next;//left to mid
        n2 = n2->next;//right to mid
    }
    n1 = n3->next;
    n3->next = NULL;
    while(n1 != NULL){//恢复列表
        n2 = n1->next;
        n1->next = n3;
        n3 = n1;
        n1 = n2;
    }
    return res;
}

【参考】程序员代码面试指南——左程云

上一篇:小白使用Eclipse 的基本设置


下一篇:Jenkins Pipeline使用File parameter上传文件并保存到workspace