2019年5月29日 第二次练习(9回文数)+2019年5月30日 第三次练习(234回文链表)

本文记录了作者在LeetCode上解题的心得,包括9.回文数和234.回文链表两道题目。对于回文数,作者从字符串对比到数学算法的转变提高了效率。而在回文链表问题上,通过快慢指针找中点,并使用头插法翻转链表进行比较,实现了时间效率的提升。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

9.回文数

因为放假了,所以变成不想营业的一天…但这才练习的第二天,看看自己的渣渣水平,还是果断打开了leetcode,从此和你相依为命,啊啊啊。

这次的题目是判断一个回文数,首先我先想到的是将整数变成字符串,然后将前后两个字符进行对比。
自己写出来的代码如下

  class Solution {
public:
    bool isPalindrome(int x) {
            if(x<0) return 0;
        	string str_x=to_string(x);
            int n=str_x.length();
           int i=0,j=n-1;
           while(str_x[i]==str_x[j]){
        	   
        	   if(n%2==0&&(i+1==j)){
        		   return 1;
        	   }
        	   if(n%2==1&&(i==j)){
        		   return 1;
        	   }
               i++;
               j--;     
           }
           return 0;
        }
    };

执行完后,发现效率并没有很高在这里插入图片描述
寻求这个思路一些别的思路
比如在上道题运用的reverse()函数

class Solution {
public:
    bool isPalindrome(int x) {
 	long rev;	
	if (x < 0) return false;//排除负数
        string str_x = to_string(x);//转换成字符串
 	std::reverse(str_x.begin(), str_x.end());//进行反转
 	stringstream out(str_x);
 	out >> rev;//结果写入rev
	return x==rev;//比较得出结果
    }
};

代码更加简洁,但执行后发现用时更多,我觉得主要是函数调用或者stringstream建立数据流的过。
在这里插入图片描述
再看了看相同的算法没有什么好的了,这时候回去看官方思路,还是用数学的算法解决这个问题

代码如下:

public boolean isPalindrome(int x) {
         int y = x;
        if (x < 0 || (x % 10 == 0 && x != 0)) {
            return false;
        }
        long newNum = 0;
        while (x != 0) {
            newNum = x % 10 + newNum * 10;
            x=x/10;
        }
        if(y == newNum)
            return true;
        return false;
    }

在这里插入图片描述
事实证明,效率确实高。

之后有一道相似的题目,判断链表是不是回文的。

234.回文链表

今天是30号,本想着昨天多写几道题,但后来自己一懒惰,导致昨天写的都没发出去,追悔莫及!!所以只能在今天补上了,今天的目标也是写完这道题,因为还想去学习编译和英语。

话不多说,开始看到这道题的时候我的想法是将链表的前半部放进栈中,再利用数据结构的特性,一一进行比较。
数据结构定义如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

我的算法开始是这么写的:

class Solution {
public:
    bool isPalindrome(ListNode* head) {
    	if(head==NULL || head->next==NULL) return true;
    	int num=0;//存放链表长度
    	ListNode *p=head;

    	while(p)//计算链表长度
    		{
    		num++;
    		p=p->next;
    		}
    	p=head;
    	int midnum;
    	if(num%2==0) midnum=num/2;
    	if(num%2==1) midnum=num/2+1;
    	stack<int> stack;
    	for(int i=0;i<midnum;i++){
    		stack.push(p->val);
    		p=p->next;
    	}
    	if(num%2==1) stack.pop();
    	while(p&&!stack.empty()){
    		   if(p->val!=stack.top()){
    			   return false;
    		   }
    		   p=p->next;
    		   stack.pop();
    	   }
    	return true;
    }
};

执行之后非常惨烈:
在这里插入图片描述
这里需要注意的一个是如何获取链表的中点位置。
方法(1)最小白的办法,遍历链表,获取链表长度,然后分奇数偶数,算出中点在哪。

        int num=0;//存放链表长度
        ListNode *p=head;
        while(p)//计算链表长度
        {
            num++;
            p=p->next;
        }
        int midnum=num/2;

方法(2)是我看到别人的代码大都这样写,用快慢指针进行实现。至今还没搞懂原理是什么,据说是因为fast指针始终是slow指针的二倍,而且这种方法不用考虑奇数偶数。

//确定中点
        while(fast && fast->next){
            fast = fast->next->next;
            mid = slow;
            slow = slow->next;
        }

完整的代码借鉴一下别人的思路,发现大家的思路都是把前半部分或者后半部分进行翻转,然后再比较,就比如这个

class Solution{
    public:
bool isPalindrome(struct ListNode* head){
    if(head == NULL || head->next == NULL) return true;
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    struct ListNode* mid = head;
    //确定中点
    while(fast && fast->next){
        fast = fast->next->next;
        mid = slow;
        slow = slow->next;
    }
    mid->next = NULL;
    //反转后半部分列表
    struct ListNode* pNode, *pNext;
    pNode = slow->next;
    slow->next = NULL;
    pNext = NULL;
    while(pNode){
        pNext = pNode->next;
        pNode->next = slow;
        slow = pNode;
        pNode = pNext;
    }
    //判断链表是否相等
    while(head){
        if(head->val != slow->val) return false;
        head = head->next;
        slow = slow->next;
    }
    return true;
}
};

和我的想法不同的是他不用栈实现对比,用两个链表实现相互比较,且指针翻转的时候也直接用链表头插法进行操作。

运行时间大大缩短,但运行空间上并不优秀,当然也算是一些进步==。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值