【Leetcode】234. 回文链表

本文介绍了如何判断一个链表是否为回文链表,提供了两种不同的解决方案。第一种方法利用数组辅助,通过双指针比较元素来判断;第二种方法通过快慢指针找到链表中点,反转后半部分链表,再进行双指针比较。这两种方法分别在时间和空间效率上有所优势。

题目描述

在这里插入图片描述

// 234. 回文链表

// 请判断一个链表是否为回文链表。

题解

// 数组辅助法
// 将链表中所有元素放进数组list中,之后设置左右指针l和r,循环令左指针右移,
// 右指针左移,令左右指针遍历的元素进行比对,如果不相等则直接返回false,
// 相等则继续移动,循环结束之后返回true。
// 执行用时:14 ms, 在所有 Java 提交中击败了13.86%的用户
// 内存消耗:50.9 MB, 在所有 Java 提交中击败了21.89%的用户
class Solution {
    public boolean isPalindrome(ListNode head) {
        List<Integer> list = new ArrayList<>();
		ListNode cur = head;
		while (cur != null) {
			list.add(cur.val);
			cur = cur.next;
		}
		
		int l = 0;
		int r = list.size() - 1;
		while (l <= r) {
			if (!list.get(l).equals(list.get(r)))
				return false;
			l++;
			r--;
		}
		return true;
    }
}


// 找链表中点 + 链表反转
// 还记得【Leetcode】876. 链表的中间结点 和 【Leetcode】206. 反转链表,
// 我们可以使用876题先找链表中点,我们在这里不要靠右的点,而是要靠左的点,
// 所以要将快慢针的快针初始化到head的next,来进行快慢针,找到中点mid之后。
// 取mid.next之后的链表,做链表反转。
// 反转链表之后,mid指针会成为反转链表的头结点,记为rightHead。
// 那我们就有没反转的左半部分链表记为leftHead,和反转之后的右半部分链表
// rightHead,双指针循环移动,从leftHead和rightHead开始出发,然后比对双
// 指针的遍历元素,如果不相同,直接返回false,如果遍历完了,直接返回true
// 
// 比如目标链表为:
//leftH
// 1 -> 2 -> 3 -> 3 -> 2 -> 1
//
// 找到中点mid有:
//leftH		mid
// 1 -> 2 -> 3 -> 3 -> 2 -> 1
//
// 翻转mid.next之后的链表有:
//leftH		mid
// 1 -> 2 -> 3    3 -> 2 -> 1
//
//leftH		mid           rightH
// 1 -> 2 -> 3    3 <- 2 <- 1
//
// 之后leftHead和rightHead一起双指针移动,如果是回文链表,指针元素一定相等,
// 否则就不是回文链表。
//
// 执行用时:5 ms, 在所有 Java 提交中击败了58.54%的用户
// 内存消耗:48.3 MB, 在所有 Java 提交中击败了57.95%的用户
class Solution {
    public boolean isPalindrome(ListNode head) {
		ListNode cur = head.next;
		ListNode mid = head;
		while (cur != null && cur.next != null) {
			cur = cur.next.next;
			mid = mid.next;
		}
		ListNode rightHead = reverseListNode(mid.next);
		ListNode leftHead = head;
		
		while (leftHead != null && rightHead != null) {			
			if (leftHead.val != rightHead.val)
				return false;
			leftHead = leftHead.next;
			rightHead = rightHead.next;
		}
		return true;
    }
	
	public ListNode reverseListNode(ListNode head) {
		if (head == null || head.next == null)
			return head;
		ListNode pre = head;
		ListNode mid = head.next;
		ListNode cur = head.next.next;
		
		pre.next = null;
		mid.next = pre;
		while (cur != null) {
			pre = mid;
			mid = cur;
			cur = cur.next;
			mid.next = pre;
		}
		return mid;
	}
}

LeetCode 234回文链表有多种解法,以下为你介绍几种常见的解法: ### 解法一:将链表复制到数组里再从两头比对 将链表元素复制到数组中,然后使用双指针从数组的两端向中间遍历,比较对应元素是否相等。如果在遍历过程中发现不相等的元素,则链表不是回文链表;如果遍历完整个数组都没有发现不相等的元素,则链表回文链表。 ```cpp #include <vector> class Solution { public: bool isPalindrome(ListNode* head) { std::vector<int> listvec; // 把链表中元素都插入数组 while (head != nullptr) { listvec.push_back(head->val); head = head->next; } // 一个迭代器从头,一个迭代器从尾 auto it_head = listvec.begin(); auto it_back = listvec.end() - 1; // 若迭代器相遇了则说明都检查完了,可以返回true while (it_back - it_head > 0) { // 检查到值不相等就返回false if ((*it_head++) != (*it_back--)) return false; } return true; } }; ``` ### 解法二:递归法 递归地遍历链表,同时使用一个指针链表头开始比较。递归过程中,先递归到链表的末尾,然后在回溯的过程中与链表指针指向的元素进行比较。 ```cpp class Solution { ListNode* frontPointer; public: 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); } }; ``` ### 解法三:快慢指针 + 反转链表 使用快慢指针找到链表的中点,然后将链表的后半部分反转,最后比较前半部分和反转后的后半部分是否相等。 ```cpp class Solution { public: bool isPalindrome(ListNode* head) { if (head == nullptr) return true; // 找到前半部分链表的尾节点并反转后半部分链表 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; } private: ListNode* reverseList(ListNode* head) { ListNode* prev = nullptr; ListNode* curr = head; while (curr != nullptr) { ListNode* nextTemp = curr->next; curr->next = prev; prev = curr; curr = nextTemp; } return prev; } 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; } }; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

锥栗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值