判断回文链表(剑指offer.027)
目录
-数组法-
-递归法-
-快慢指针-
-题目-
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/bool isPalindrome(struct ListNode* head) {}
(注意:这题的条件为不带头结点的单链表,head就是链表的第一个结点)
(这里函数返回类型bool使用方法是直接返回false或者true。)
看到题目,博主第一想法就是头插法再建立一个链表,遍历两个链表就能得出该链表是否是回文的。但这个思路实现起来容易出错,以至于我改了n遍都没改对= =。
下面记录三个力扣官方给的三个思路(图片来源也是力扣官方)
-数组法-
将链表的值依次放进数组,再判断数组里的数是不是回文序列。
bool isPalindrome(struct ListNode* head){struct ListNode *p;int a[100000], i = 0;p = head;while(p){a[i++] = p -> val;p = p -> next;}int l = 0, r = i - 1;while(1){if(l >= r){break;}if(a[l] != a [r]){return false;}l ++;r --;}return true; }
-递归法-
基本思路是创建两个指针:frontNode从前面开始遍历链表,currentNode从后面开始遍历链表。这个方法的思路不难理解,复杂的是currentNode通过递归调用函数来从链表尾开始往前遍历。
struct ListNode* frontNode;bool recursivelyCheck(struct ListNode* currentNode) {if (currentNode != NULL) {if (!recursivelyCheck(currentNode -> next)) {return false;}if (currentNode -> val != frontNode -> val) {return false;}frontNode = frontNode -> next;}return true; }bool isPalindrome(struct ListNode* head) {frontNode = head;return recursivelyCheck(head); }
这里介绍一下currentNode实现其功能的过程
这个过程涉及到栈,但是不用学到栈也能看懂,只需要知道栈是后进先出就行。
假设该链表存有五个数据5-6-1-7-5(不为回文序列),从主函数调用recursivelyCheck(head)开始,这一步将currentNode指向#0(这里用'#数字'来表示第几个结点)。currentNode不为null所以执行if,计算机确定了currentNode的下一个结点为#1,便将这个结点的值传入递归函数。(在调用函数前,计算机会将这个信息在栈中记录他在哪里)接下来再调用函数recursivelyCheck(#1)将currenyNode指向#1,同样的currentNode不为null所以执行if,计算机确定了currentNode的下一个结点为#2,再将其传入递归函数,再在栈中记录。再调用函数...
-信息在栈中存储的模式如下图-
(从recursivelyCheck(head)这一步开始入栈)
递归调用进行到recursivelyCheck(#4)时,currentNode仍不为null所以执行if,再下一步时递归进行到recursivelyCheck(NULL),因为链表里共有五个数,#4 -> next就是空指针NULL。此时if不执行,直接返回true给上一级。
这一级currentNode指向#4,!true为假故不返回flase,执行currentNode指向#4为5,frontPointer指向#0为5,两者相等故不返回false,然后frontPointer后移一个结点,来到最后一行代码,返回true给上一级。栈顶的信息移除 (如图,原本最顶端的信息移除)。
这一级currentNode指向#3,同样不返回false,执行currentNode指向#3为7,frontPointer指向#1为6,两者不相等故在这一步直接返回false给上一级。(可以知道若每一次currentNode和frontPointer都相等的话最后会返回true给原函数。)
这一级currentNode指向#2, !false为真故直接返回false给上一级。从这以后就不用考虑两个指针的值了,因为false会被一层层返回给原函数。
-快慢指针-
基本思路是将链表的后半部分反转,再比较前后两部分是否相同。
当然可以遍历链表得到链表长度,再取中间结点,但是这里使用了快慢指针的奇特方法。即创建快指针和慢指针,初始都指向head,慢指针每次移动一个结点,快指针每次移动两个结点直到快指针的下一次移动指向NULL,此时慢指针指向的结点就是中间结点。若链表结点为奇数个,易得中心结点不影响后续结果。
struct ListNode* reverseList(struct ListNode* head) {struct ListNode* prev = NULL;struct ListNode* curr = head;while (curr != NULL) {struct ListNode* nextTemp = curr->next;curr->next = prev;prev = curr;curr = nextTemp;}return prev; }//三指针法反转链表struct ListNode* endOfFirstHalf(struct ListNode* head) {struct ListNode* fast = head;struct ListNode* slow = head;while (fast->next != NULL && fast->next->next != NULL) {fast = fast->next->next;slow = slow->next;}return slow; }//使用快慢指针找到链表的中心位置bool isPalindrome(struct ListNode* head) {if (head == NULL) {return true;}// 找到前半部分链表的尾节点并反转后半部分链表struct ListNode* firstHalfEnd = endOfFirstHalf(head);struct ListNode* secondHalfStart = reverseList(firstHalfEnd->next);// 判断是否回文struct ListNode* p1 = head;struct ListNode* p2 = secondHalfStart;bool result = true;while (result && p2 != NULL) {if (p1->val != p2->val) {result = false;}p1 = p1->next;p2 = p2->next;}// 还原链表并返回结果firstHalfEnd->next = reverseList(secondHalfStart);return result; }
时间复杂度与空间复杂度的控制是算法的精髓,上面三个方法有不同的时间,空间复杂度,因为博主这方面了解尚浅,故不在这里具体分析。
判断回文链表(剑指offer.027)相关推荐
- 从尾到头打印链表---剑指Offer
从尾到头打印链表 输入一个链表,从尾到头打印链表每个节点的值. 解题思路: 1. 将带有头结点的链表顺序的从头到尾加入到ArrayList集合 2. 使用Collections工具类将ArrayLis ...
- 【博客搬家旧文】剑指offer [ java ] 面试题10 斐波那契数列
契波那契数列最常见的解法,递归如下: public class Solution {public int Fibonacci(int n) {if(n == 0)return 0;else if(n ...
- asp 判断数组等于_剑指Offer(牛客版)--面试题4:二维数组中的查找
SCDN博客:https://blog.csdn.net/weixin_41923658 微信公众号:「汤姆鱼」 -------------------------------------手动分割线- ...
- 3、从尾到头打印链表------------剑指offer系列
题目 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList. 分析 要了解链表的数据结构: val属性存储当前的值,next属性存储下一个节点的引用. 要遍历链表就是不断找到当前节点的nex ...
- Java利用二维数组判断节假日_《剑指offer》面试题3 二维数组中的查找 Java版
(二维数组,每行递增,每列递增.输入二维数组和一个整数,判断数组中是否含有此数.) 我的方法:拿到题目,根据题目条件我提取出这样一个特性:一个数的右边和下面的数都比它大.于是就可以写出一种递归的方法: ...
- 面试题5:从尾到头打印单链表(链表--剑指offer)
题目描述 输入一个链表,从尾到头打印链表每个节点的值. //方法一:从头到尾打印单链表,将结果存放至vector中,然后将vector倒置 vector<int> printListFro ...
- Leetcode刷题笔记——剑指offer II (一)【整数、数组、字符串、链表】
目录 整数 剑指 Offer II 001. 整数除法 剑指 Offer II 002. 二进制加法 剑指 Offer II 003. 前 n 个数字二进制中 1 的个数 剑指 Offer II 00 ...
- 力扣OJ 剑指 Offer II
目录 剑指 Offer II 001. 整数除法 剑指 Offer II 002. 二进制加法 剑指 Offer II 003. 前 n 个数字二进制中 1 的个数 剑指 Offer II 004. ...
- 判断字符串_python实现--判断回文字符串、回文链表、回文数
所谓回文字符串,就是正读和反读都一样的字符串,比如"level"或者"noon"等等就是回文串.即是对称结构Python系列教程,免费获取,遇到bug及时反馈, ...
最新文章
- 一个牛逼的 多级缓存 实现方案!
- 2004-5-12+ 用DataSet实现分页
- linux c++ 多进程初步01
- 设计模式_4_原型模式(对象的拷贝)
- linux安装mvn及nexus远程仓库
- wps linux 哪个版本好用吗,WPS Linux版与国产统一操作系统UOS完成适配:体验追上Wintel...
- javaee 学习书籍推荐
- 白帽子讲Web安全(一)浏览器安全
- 表达式的LenB(123程序设计ABC)的值是
- 免费稳定的APP分发托管平台,支持应用合并、内测分发、扫码下载
- 简简单单说外键和级联
- 碉堡了!最大 18 禁网站用 AI 和 ML 来做视频分类加标签
- kafka和raft共识机制
- flutter 状态管理 flutter_bloc 的使用以及总结
- clap与slap_slap-slap和clap有什么区别?slap和c – 手机爱问
- 通讯录中每个通讯者的信息包括编号、姓名、性别、电话、E-mail地址;采用单链表结构存储
- 利用C++创建一个游戏(9)愤怒的小鸟(代码+注释)
- python爬取知乎文章_Python爬取知乎日报,推送到kindle
- 某些有趣的API接口
- 养子女对养父母和亲生父母都要有赡养义务吗
热门文章
- python elasticsearch
- tensorflow 进阶(二),BP神经网络
- mysql第五章项目二_Todo List:Node+Express 搭建服务端毗邻Mysql – 第五章(第1节)
- 37. Leetcode 100. 相同的树 (二叉树-二叉树性质)
- (纯干货)万字长文,数据分析利器 pandas 全教程
- 来个邪恶假说,假如有人把支付宝所有存储服务器炸了,我们在里边的钱是不是都丢了?
- ClickHouse 在字节跳动广告场景的应用
- 【python进阶】_多线程多进程
- LeetCode-剑指 Offer 03. 数组中重复的数字
- 详解Numpy的广播机制