算法习题42:修改append函数,求链表并集

本文探讨如何在链表结构下找到并集,通过改进的append方法,实现时间复杂度为O(n)。算法思路是遍历第一个链表并与第二个链表首位元素比较,找到相交部分,若无法直接连接则交换链表位置尝试。注意考虑链表可能存在的环、相交及空链表情况。
修改append函数,利用这个函数实现
两个非降序链表的并集1->2->3 和 2->3->5 并为 1->2->3->5

另外只能输出结果,不能修改两个链表的数据。

---------------------------------------------------------------

首先需要找出两个集合相交的部分,并且头尾相交,可是这里是链表结构,我们无法从后面往前找,想用递归似乎也无法实现。

这里先想到利用两个循环来遍历,找出他们共有的,经过改进可以把时间算法复杂度改成O(n) 

有一个很明显的规律,如果找到了一个相同的元素,那么我们需要判断的是剩下的元素是否也相同。例如

1 2 3 和2 3 5

当我们发现2相同,我们比较下一个元素,都是3,然后再比较时候发现有一个链表到结尾了,那么就可以链接成1 2 3 5

这样的复杂度只需要第一个链表的长度决定


算法:

假设第一个链表结尾和第二个链表首部相连:

我们只需遍历第一个链表的元素来和第二个链表的首位元素相比,相同则比较第一个链表下一个元素和第二个链表的下一个元素,如果能够比到第一个链表结尾,那么链接上,

如果中途不想等,则把第二个链表重新指回第一个元素,继续比较第一个链表剩余元素和第二个链表是否相连接,

如果比到最后不能链接,那么交换第一个和第二个链表,判断是否第二个链表和第一个链表相连接,

如果可以输出结果,不行则返回false


注:(有几个问题,我没有实现,但面试中希望大家能够想到)

1、链表是否存在环!

2、两个链表是否相交!

3、如果链表为空呢?

//============================================================================
// Name        : Append.cpp
// Author      : YLF
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
using namespace std;

struct Node{
	int value;
	Node* next;
};

void Add(Node* &head, int value);
void PrintHead(Node* head);
bool Append(Node* head1, Node* head2);
void Print(Node* p1, Node* p2, int n);

int main() {

	Node* head1 = NULL;
	Node* head2 = NULL;

	int input = 0;

	while(true){
		cin>>input;
		if(input != -1)
			Add(head1, input);
		else
			break;
	}

	while(true){
		cin>>input;
		if(input != -1)
			Add(head2, input);
		else
			break;
	}

	if(!Append(head1, head2))
		cout<<"no intercept!";
	return 0;
}

void Add(Node* &head, int value){
	Node* p = new Node();
	p->value = value;
	p->next = NULL;

	if(head == NULL)
		head = p;
	else{
		Node* temp = head;
		while(temp->next != NULL)
			temp = temp->next;
		temp->next = p;
	}
}
/*
 * 时间复杂度O(n)
 */
bool Append(Node* head1, Node* head2){
	Node* p1 = head1;
	Node* p2 = head2;

	int n = 0, tempN = 0;//n记录相交的位置,如果第一次相等的不是交集位置,那么n+tempN
	bool flag = false;//标记前面的元素是否相等
	bool isSwap = false;

	while(true){
		while(p1->value != p2->value){

			if(flag){
				p2 = head2;
				flag = false;
				n = n + tempN;
				tempN = 0;
			}else{
				p1 = p1->next;
				n++;
			}

			if(p1 == NULL){
				//交换head1,head2
				if(isSwap)
					return false;
				isSwap = true;
				Node* temp = head1;
				head1 = head2;
				head2 = temp;

				p1 = head1;
				p2 = head2;
				n=0;
				flag = false;
				continue;
			}
		}

		flag = true;
		p1 = p1->next;
		p2 = p2->next;
		tempN++;

		if(p1 == NULL){
			Print(head1,head2,n);
			return true;
		}
		if(p2 == NULL){
			p2 = head2;
			n = n+tempN;
			tempN = 0;
		}
	}
}

void Print(Node* p1, Node* p2, int n){
	while(n-->0){
		cout<<p1->value<<" ";
		p1 = p1->next;
	}

	while(p2 != NULL){
		cout<<p2->value<<" ";
		p2 = p2->next;
	}
}

给几个测试集

2 3 4 5 -1
1 2 3 1 2 3 4 5 -1
1 2 3 1 2 3 4 5 

2 3 4 5 -1
2 3 4 2 3 4 1 -1
no intercept!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值