简单题也要这么写吗??力扣 回文链表 多种判断 附解析c语言实现

题目

在这里插入图片描述
题目非常简单,无非就是判断一个没用头结点的指针,是否为回文链表,但是简单的题目往往值得更深的思考。该题目有很多的解法,想要在时间击败百分百的话,不仅仅是代码本身,可能跟电脑还有一定的关系。
全遍历,入数组:

思路很容易想到,第一次遍历完整个链表,一边遍历,一遍把节点入数组
并计算长度,最后用数组中的元素判断,规避了指针不能随意访问的难受
问题。时间:O(N),空间:O(N)。
int q[70000];
bool isPalindrome(struct ListNode* head){
    struct ListNode* p = head;
    int len = 0;
    while(p){
        q[len++] = p->val;
        p = p->next;
    }
    for(int i = 1; i <= len/2; i++)
        if(q[i] != q[len-i+1]) return false;
    return true;
}

全遍历,入数组,做双向判断,其实就是对上面一个循环的改动。。

bool isPalindrome(struct ListNode* head) {
    int vals[50001], vals_num = 0;
    while (head != NULL) {
        vals[vals_num++] = head->val;
        head = head->next;
    }
    for (int i = 0, j = vals_num - 1; i < j; ++i, --j) {
        if (vals[i] != vals[j]) {
            return false;
        }
    }
    return true;
}

快慢指针,链表逆置:
设置快慢指针,都从头开始,快指针走每次走两步,慢指针每次走一步,那么慢指针最后要么到链表的中间元素,要么到元素中间元素的左边元素(这取决于链表长度为奇数还是偶数)。最后将前一段或者后一段逆置,判断。该方法有问题,在逆置完之后,如果在访问链表的话会出问题,因此,还需要将其翻转回来,但是题目没有要求不改变链表,我也就懒得写了,同理,可以在该方法机理上进行优化。实现略去翻转的步骤。

/**
 * 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;
    if(head->next->next == NULL){
        if(head->val == head->next->val)
            return true;
        else
            return false;
    }
    struct ListNode *fastp, *slowp;
    fastp = head->next->next;
    slowp = head->next;
    while(fastp && fastp->next != NULL){
        fastp = fastp->next->next;
        slowp = slowp->next;
    }
    struct ListNode *prep, *nextp;
    prep = nextp = NULL;
    while(head != slowp){
        nextp = head->next;
        head->next = prep;
        prep = head;
        head = nextp;
    }
    if(fastp != NULL && fastp->next == NULL)
        slowp = slowp->next;
    while(prep != NULL){
        if(prep->val != slowp->val)
            return false;
        prep = prep->next;
        slowp = slowp->next;
    }
    return true;
}

快慢指针,入半栈:

优化上面的方案,省去了一半的循环,同时防止了链表结构的改变。结果
如下,完美。emm,也不是,空间是个问题,不过在这个空间爆炸,时间
有限的时代,谁又会在乎那点空间呢。

在这里插入图片描述

#define maxsize 100000
bool isPalindrome(struct ListNode* head){
	if(!head)//判除三种特殊情况 
		return true;
	if(!head->next)
		return true; 
	if(!head->next->next)
		if(head->val!=head->next->val) return false;
		else 								 return true;
	struct ListNode *t=head,*q=head,*p=head;
	struct ListNode **stack=(struct ListNode **)malloc(sizeof(struct ListNode*)*maxsize);
	int top=-1;
    stack[++top]=t;
	while(p->next&&p->next->next){
		q=q->next;
        stack[++top]=q;
		p=p->next->next;
	}
	if(!p->next){//判断奇偶  奇数p->next为空,偶数不为空 
        for(int i=top;i>=0;i--,q=q->next){
			if(stack[i]->val!=q->val){
				return false;
			}
		}
	}
	else{
		q=q->next;
		for(int i=top;i>=0;i--,q=q->next){
			if(stack[i]->val!=q->val)
				return false;
		}
	}
	free(stack);
    return true;
}

链表反转:

思路新颖,可以自己尝试在本子上画一下,画出来是不难理解的。
bool isPalindrome(struct ListNode* head){
    if(head == NULL) return true;
    int len = 0;
    struct ListNode *p = head;
    while(p){
        len++;
        p = p->next;
    }
    if(len == 1) return true;
    if(len == 2){
        if(head->val == head->next->val) return true;
        else return false;
    }
    if(len == 3){
        if(head->next->next->val == head ->val) return true;
        else return false;
    }
    int tmp = (len-1)/2, flag = 0;
    if(len%2 == 1) flag = 1;
    len = (len+1)/2;
    p = head;
    while(len){
        head = head->next;
        len--;
    }
    struct ListNode *q = p, *r = p->next->next;
    p = p->next;
    q->next = NULL;
    while(tmp){
        p->next = q;
        q = p;
        p = r;
        r = r->next;
        tmp--;
    }
    if(flag == 1) q = q->next;
    while(head){
        if(q->val != head->val) return false;
        q = q->next, head = head->next;
    }
    return true;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值