力扣234. 回文链表 反转链表法、栈法、双指针法、快慢指针法、递归法

回文链表
请判断一个链表是否为回文链表。
示例 1:

输入: 1->2
输出: false

示例 2:

输入: 1->2->2->1
输出: true

进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

1 <= ListNode.size <= 100000

解法一:反转链表法
根据回文的定义,若一个数字从后往前读跟从前往后读是一样的,那么即为回文数,所以我们可以将这个链表反转,然后遍历俩个链表看看是否相同即可,这里反转链表函数为本人自己写出的,感兴趣的朋友可以自己尝试去看懂并思考其他解法,也是弄懂链表的一个很好的入门级题目,同样也是大厂面试易问的题目。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
  ListNode* reverseList(ListNode* head) {//反转链表函数
	if (!head) return nullptr;
	ListNode* a = new ListNode(head->val);
	head = head->next;
	while (head) {
		ListNode* b = new ListNode(head->val);
		b->next = a;
		a = b;
		head = head->next;
	}
	return a;
}
bool isPalindrome(ListNode* head) {//判断是否为回文链表
	ListNode* a = head;
	a = reverseList(a);
	while (head) {
		if (head->val != a->val) return false;
		head = head->next;
		a = a->next;
	}
	return true;
}

解法二:栈法
首先将链表的所有值压栈,再从链表表头开始不断的与栈中元素对比,同样达到了从前后对比链表值的目的。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
bool isPalindrome(ListNode* head) {
	stack<int> x;
	ListNode* a = head;
	while (a) {
		x.push(a->val);
		a = a->next;
	}
	while (head) {
		int p = x.top();
		if (p != head->val) return false;
		x.pop();
		head = head->next;
	}
	return true;
}

解法三:双指针法
因为链表无法直接获取中间的值,只能一个个遍历,所以这种思路是我们先将链表中的数值全部存放到列表或者数组中去(列表与数组使用起来一样),然后在使用双指针法判断是否为回文。
双指针法具体实现:
在起点和结尾各放置一个指针,每一次循环判断两个指针指向的元素是否相同,若不同则退出循环返回false,相同则不断地将两个指针向内移动直到两个指针相遇为止。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
 bool isPalindrome(ListNode* head) {
        vector<int> x;//容器,使用数组也可
        while (head) {
            x.push_back(head->val);
            head = head->next;
        }
        for (int i = 0, j = (int)x.size() - 1; i < j; i++, j--) 				
            if (x[i] != x[j]) return false;
        return true;
    }

解法四快慢指针法:
这种方法是五种方法中唯一一个达到进阶要求O(1) 空间复杂度的。
首先我们应当找到前半部分链表的尾节点,随后反转后半部分链表,形成俩个链表,本质上也是从后往前遍历。再遍历俩个链表是否回文,如果有需要可以恢复链表,当然不恢复也能过题,不过作为一个优秀的程序员应当保持良好的习惯,一般使用函数的人总是不希望使用函数后链表的结构发生了变化,这里同样需要使用到第一种解法中给出的反转链表函数。
那么如何找到前半部分链表的尾节点?第一种找法是直接遍历一遍链表,然后得到链表的数目,从而得到中间结点的位置,那么聪明一点的做法就是快慢指针法,在表头设置俩个指针,快指针一次移动俩个数位,慢指针一次移动一个数位,当快指针移动到表尾,则慢指针恰好位于链表的中间。

bool isPalindrome(ListNode* head) {
        // 找尾节点
        ListNode* firstHalfEnd = endOfFirstHalf(head);
        //反转后半部分的链表
        ListNode* secondHalfStart = reverseList(firstHalfEnd->next);

       
        ListNode* p1 = head;
        ListNode* p2 = secondHalfStart;
        bool result = true;
        while (result && p2 != nullptr) {//判断回文
            if (p1->val != p2->val) {
                result = false;
            }
            p1 = p1->next;
            p2 = p2->next;
        }        
		//还原链表,若为了更快的提交速度可以不写
        firstHalfEnd->next = reverseList(secondHalfStart);
        return result;
    }

ListNode* reverseList(ListNode* head) {//反转链表函数
	if (!head) return nullptr;
	ListNode* a = new ListNode(head->val);
	head = head->next;
	while (head) {
		ListNode* b = new ListNode(head->val);
		b->next = a;
		a = b;
		head = head->next;
	}
	return a;

ListNode* endOfFirstHalf(ListNode* head) {//寻找尾结点
        ListNode* fast = head;
        ListNode* slow = head;
        while (fast->next != nullptr && fast->next->next != nullptr) {
            fast = fast->next->next;
            slow = slow->next;
        }
        return slow;
    }

解法五:递归法

bool recursivelyCheck(ListNode* currentNode) {
        if (currentNode != nullptr) {
            if (!recursivelyCheck(currentNode->next)) return false;
            if (currentNode->val != frontPointer->val) return false;
            frontPointer = frontPointer->next;
        }
        return true;
    }

    bool isPalindrome(ListNode* head) {
        frontPointer = head;
        return recursivelyCheck(head);
    }
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值