leetcode链表相关解题技巧

之前刷leetcode,很多链表的题目刷起来很慢,很费劲,说到底,对链表这个数据结构有种不信任感,因为每次经过一个节点之后就没有办法返回了(单项链表),平时用习惯了数组,对这种变化有点不适应。

这里说一说我在刷题过程中解决链表相关问题所用的技巧,以及如何更好的使用链表

一、dummyHead

leetcode里面传进来的head是带有数据的,这个没有任何节点指向head,因此对head的修改有时会比较的麻烦,因此可以先建立一个假想节点指向head,以后需要返回head时,直接返回:dummyHead->next即可。

ListNode* dummyhead = &ListNode(-1);

这个技巧应该是最常用的了。

二、断链

这个操作通过函数cut(l, n)实现,其作用是:将链表 l 切掉前 n 个节点,并返回后半部分的链表头。

// 将链表head的前n个节点取下来,并返回后续链表的头结点
ListNode* cut(ListNode* head, int n) {
	ListNode *p = head;
	while (p != NULL && --n)
		p = p->next;
	if (p == NULL)
		return NULL;
	ListNode *q = p->next;
	p->next = NULL;
	return q;
}

这个操作很重要,因为实际上,当题目给我们一个链表头,告诉我们需要对该链表做什么操作时,我们并不知道head的前面有什么,也没有办法知道,因为给的链表是单向的。

而这个断链操作可以减小问题的规模,假设链表长度为n,每次断链之后得到的链表长度为m,相比于原来的问题规模缩小了很多,这意味着许多问题都可以用分治法来做了。

当问题规模减小到一定程度的时候,就可以直接解决了,我们通过合并每个解决了的子问题来得到原问题的解。

三、合并

之前说过使用分治法,其中关键的一步:合并每个子问题的解。
一般链表的合并方法是首尾相接,这个没什么好说的,这里说一说有序链表的合并

// 将两个有序链表合并为一个大的有序链表
ListNode* merge(ListNode* list1, ListNode* list2) {
	ListNode dummyHead(-1);
	ListNode *p = &dummyHead;
	
	while (list1 != NULL && list2 != NULL) {
		if (list1->val > list2->val) {
			p->next = list2;
			list2 = list2->next;
			p = p->next;
		}
		else {
			p->next = list1;
			list1 = list1->next;
			p = p->next;
		}
	}
	if (list1)
		p->next = list1;
	if (list2)
		p->next = list2;
	return dummyHead.next;
}

四、快慢指针

什么是快慢指针?

就是定义两个指针,一个指针(慢指针)的移动速度为v,另一个指针(快指针)速度为2v,如此一来,经过相同的时间,快指针走过的路程是慢指针的2倍。

C++代码:

        ListNode *fast = head, *slow = head;
        while(fast && fast->next){
            fast = fast->next->next;
            slow = slow->next;
        }

你可能感兴趣的:(LeetCode刷题技巧,链表)