算法题C++(三)

本博客目录

  • 将单向链表按某值划分成左边小、中间相等、右边大的形式
  • 复制含有随机指针节点的链表
  • 两个单链表相交的一系列问题

将单向链表按某值划分成左边小、中间相等、右边大的形式

给定一个单向链表的头节点head,节点的值类型是整型,再给定一个整数p。实现一个调整链表的函数,将链表调整为左部分都是值小于 p的节点,中间部分都是值等于p的节点,右部分都是值大于 p的节点。

空间复杂度为O(N)的算法

//建立辅助数组,先在数组上排序,之后连接
//空间复杂度O(n)
ListNode* listPartition1(ListNode* head, int num) {
	if (head == NULL || head->next == NULL) {
		return head;
	}
	int i = 0;
	ListNode* cur = head;
	vector<ListNode*> arr;
	while (cur != NULL){
		i++;
		arr.push_back(cur);
		cur = cur->next;
	}
	arrPartition(arr, num);
	for (i = 1; i != arr.size(); i++) {
		arr[i - 1]->next = arr[i];
	}
	arr[i - 1]->next = NULL;
	return arr[0];
}

void arrPartition(vector<ListNode*> arr, int num) {
	int length = arr.size();
	int less = -1;
	int more = length;
	int cur = 0;
	while (cur >= more) {
		if (arr[cur]->val == num) {
			cur++;
		}
		else if (arr[cur]->val < num) {
			swap(arr, cur++, ++less);
			less++;
		}
		else {
			swap(arr, cur, --more);
		}
	}
}

void (vector<ListNode*> arr, int i, int j) {
	ListNode* tmp = arr[i];
	arr[i] = arr[j];
	arr[j] = tmp;
}

空间复杂度为O(1)的算法

//将链表分成三个部分:
//分别为小于p、等于p、大于p
//分别用一串链表连接起来,最终,连接成一个链表
ListNode* listPartition2(ListNode* head, int num) {
	ListNode* sH = NULL;
	ListNode* sT = NULL;
	ListNode* eH = NULL;
	ListNode* eT = NULL;
	ListNode* bH = NULL;
	ListNode* bT = NULL;
	ListNode* next = NULL;
	while (head != NULL) {
		next = head->next;
		head->next = NULL;
		if (head->val < num) {
			if (sH == NULL) {
				sT = head;
				sH == head;
			}
			else {
				sT->next = head;
				sT = head;
			}
		}
		else if (head->val > num) {
			if (bH == NULL) {
				bH = head;
				bT = head;
			}
			else {
				bT->next = head;
				bT = head;
			}
		}
		else{
			if (eH == NULL) {
				eH = head;
				eT = head;
			}
			else {
				eT->next = head;
				eT = head;
			}
		}
		head = next;
	}
	if (sT != NULL) {
		sT->next = eH;
		eT = eT == NULL ? sT : eT;
	}
	if (eT != NULL) {
		eT->next = bH;
	}
	return sH != NULL ? sH : eH != NULL ? eH : bH;
}

复制含有随机指针节点的链表

ListNode* copyListWithRand(ListNode* head) {
	if (head == NULL) {
		return NULL;
	}
	ListNode* cur = head;
	while (cur != NULL) {
		ListNode* node = new ListNode(cur->val);
		node->next = cur->next;
		cur->next = node;
		cur = node->next;
	}
	cur = head;
	while (cur != NULL) {
		ListNode* node = cur->next;
		node->random = cur->random == NULL ? NULL : cur->random->next;
		cur = node->next;
	}
	cur = head;
	ListNode* cloneHead = head->next;
	while (cur->next != NULL){   //注意边界处理,不然容易溢出
		ListNode* node = cur->next;
		cur->next = node->next;
		cur = node;
	}
	return cloneHead;
}

两个单链表相交的一系列问题

单链表可能有环,也可能无环。给定两个单链表的头节点 head1和head2,这两个链表可能相交,也可能不相交。请实现一个函数, 如果两个链表相交,请返回相交的第一个节点;如果不相交,返回null 即可。

/*
这个问题要考虑几种情况:
1. 两个链表都是单链表,判断入环节点
2. 两个链表都有环,判断入环节点
3. 一个链表有环,一个链表无环,则一定不想交。因为它们都是单链表。
*/
ListNode* findFirst(ListNode* head1, ListNode* head2) {
	ListNode* loop1 = isLoop(head1);
	ListNode* loop2 = isLoop(head2);
	ListNode* firstNode = NULL;
	if (loop1 == NULL && loop2 == NULL) {
		firstNode = noLoop(head1, head2);
	}
	else if (loop1 != NULL && loop2 != NULL) {
		firstNode = bothLoop(head1, head2, loop1, loop2);
	}
	else {
		firstNode = NULL;
	}
	return firstNode;
}

//判断一个链表是否有环
//返回入环的节点
 ListNode* isLoop(ListNode* head) {
	if (head == NULL || head->next == NULL || head->next->next == NULL) {
		return NULL;
	}
	ListNode* slow = head->next;
	ListNode* fast = head->next->next;
	while (slow != fast) {
		if (fast->next == NULL || fast->next->next == NULL) {
			return NULL;
		}
		slow = slow->next;
		fast = fast->next->next;
	}
	fast = head;
	while (slow != fast) {
		slow = slow->next;
		fast = fast->next;
	}
	return slow;
}

//都无环的情况
ListNode* noLoop(ListNode* head1, ListNode* head2) {
	if (head1 == NULL || head2 == NULL) {
		return NULL;
	}
	int n = 0;
	ListNode* cur1 = head1;
	ListNode* cur2 = head2;
	while (cur1->next != NULL) {
		n++;
		cur1 = cur1->next;
	}
	while (cur2->next != NULL){
		n--;
		cur2 = cur2->next;
	}
	if (cur1 != cur2) {
		return NULL;
	}
	cur1 = n > 0 ? head1 : head2;
	cur2 = cur1 == head1 ? head2 : head1;
	n = abs(n);
	while (n != 0) {
		n--;
		cur1 = cur1->next;
	}
	while (cur1 != cur2) {
		cur1 = cur1->next;
		cur2 = cur2->next;
	}
	return cur1;
}

//都有环的情况
ListNode* bothLoop(ListNode* head1, ListNode* head2, ListNode* loop1, ListNode* loop2) {
	ListNode* cur1 = NULL;
	ListNode* cur2 = NULL;
	if (loop1 == loop2) {
		int n = 0;
		cur1 = head1;
		cur2 = head2;
		while (cur1 != loop1) {
			n++;
			cur1 = cur1->next;
		}
		while (cur2 != loop2) {
			n--;
			cur2 = cur2->next;
		}
		cur1 = n > 0 ? head1 : head2;
		cur2 = cur1 == head1 ? head2 : head1;
		n = abs(n);
		while (n != 0){
			n--;
			cur1 = cur1->next;
		}
		while (cur1 != cur2){
			cur1 = cur1->next;
			cur2 = cur2->next;
		}
		return cur1;
	}
	else {
		cur1 = loop1->next;
		while (cur1 != loop1){
			if (cur1 == loop2) {
				return loop1;
			}
			cur1 = cur1->next;
		}
		return NULL;
	}
}

参考

牛客网左程云算法课

猜你喜欢

转载自blog.csdn.net/weixin_39953502/article/details/79831321