HRBUXG ACM —链表
转圈打印矩阵
【题目】
给定一个整型矩阵matrix,请按照转圈的方式打印它。
例如
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
打印结果为:1,2,3,4,8,12,16,15,14,13,9,5,6,7,11, 10
【要求】额外空间复杂度为O(1)。
核心思想:将矩阵分圈、再循环打印
设计一个函数,只打印最外圈,这里取最外圈的左上角顶点和左下角顶点的坐标,表示一个子矩阵,按照从外到里的顺序打印每个子矩阵就可以完成转圈打印。
#include<iostream>
#include<stack>
#include<queue>
#include<cstdlib>
#include<limits.h>
using namespace std;
void printEdge(int *matrix[], int tR, int tC, int dR, int dC);
void spiralOrderPrint(int *matrix[],int row,int col){
int tR=0;
int tC=0;
int dR=row-1;
int dC=col-1;
while(tR<=dR && tC<=dC) {
printEdge(matrix, tR++, tC++, dR--,dC--);
}
}
void printEdge(int *matrix[], int tR, int tC, int dR, int dC){
if(tR==dR) {
//子矩阵只有一行时
for(int i=tC;i<=dC;i++) {
cout<<matrix[tR][i]<<" ";
}
}else if(tC==dC) {
//子矩阵只有一列时
for(int i=tR;i<=dR;i++){
cout<<matrix[i][tC]<<" ";
}
}else{
//一般情况
int curC=tC;
int curR=tR;
while(curC!= dC) {
cout<<matrix[tR][curC]<<" ";
curC++;
}
while(curR!= dR) {
cout<<matrix[curR][dC]<<" ";
curR++;
}
while(curC!= tC) {
cout<<matrix[dR][curC]<<" ";
curC--;
}
while(curR!= tR) {
cout<<matrix[curR][tC]<<" ";
curR--;
}
}
}
void printMatrix(int *matrix[],int row,int col) {
for(int i=0;i<row;i++) {
for(int j=0;j<col;j++) {
cout<<matrix[i][j]<<"\t";
}
cout<<"\n";
}
}
int main()
{
int row,col;
cin>>row>>col;
int **matrix=(int **)malloc(sizeof(int)*row);
int *p[row+1];
for(int i=0;i<row;i++)
{
matrix[i]=(int *)malloc(sizeof(int)*col);
for(int j=0;j<col;j++)
{
cin>>matrix[i][j];
}
}
for(int i=0;i<row;i++){
p[i]=matrix[i];
}
spiralOrderPrint(p,row,col);
}
旋转正方形矩阵
【题目】 给定一个整型正方形矩阵matrix,请把该矩阵调整成 顺时针旋转90度的样子。
【要求】 额外空间复杂度为O(1)。
#include<iostream>
#include<stack>
#include<queue>
#include<cstdlib>
#include<limits.h>
using namespace std;
void rotateEdge(int *m[], int tR, int tC, int dR, int dC);
void rotate(int *matrix[],int row,int col)
{
int tR = 0;
int tC = 0;
int dR = row - 1;0
int dC = col - 1;
while (tR < dR)
{
rotateEdge(matrix, tR++, tC++, dR--, dC--);
}
}
void rotateEdge(int *m[], int tR, int tC, int dR, int dC)
{
int times = dC - tC;
int tmp = 0;
for (int i = 0; i != times; i++)
{
tmp = m[tR][tC + i];
m[tR][tC + i] = m[dR - i][tC];
m[dR - i][tC] = m[dR][dC - i];
m[dR][dC - i] = m[tR + i][dC];
m[tR + i][dC] = tmp;
}
}
void printMatrix(int *matrix[],int row,int col)
{
for (int i = 0; i != row; i++)
{
for (int j = 0; j != col; j++)
{
cout<<matrix[i][j] << " ";
}
cout<<endl;
}
}
int main()
{
int row,col;
cin>>row>>col;
int **matrix=(int **)malloc(sizeof(int)*row);
int *p[row+1];
for(int i=0;i<row;i++)
{
matrix[i]=(int *)malloc(sizeof(int)*col);
for(int j=0;j<col;j++)
{
cin>>matrix[i][j];
}
}
for(int i=0;i<row;i++){
p[i]=matrix[i];
}
printMatrix(p,row,col);
rotate(p,row,col);
cout<<"========="<<endl;
printMatrix(p,row,col);
return 0;
}
反转单向和双向链表
【题目】 分别实现反转单向链表和反转双向链表的函数。
【要求】 如果链表长度为N,时间复杂度要求为O(N),额外空间 复杂度要求为O(1)
#include<iostream>
using namespace std;
const int N = 6;
typedef int DataType;//定义数据类型
typedef struct node{//创建链表node
DataType data;
struct node* next;
}LinkedNode,*LinkList;
LinkList CreateList(DataType a[N])//建表函数
{
LinkedNode* ListHead = new LinkedNode();
ListHead->data= a[0];
ListHead->next= NULL;
for(int i = N - 1;i >= 1;i --)
{
LinkedNode* p = new LinkedNode();
p->data = a[i];
p->next = ListHead->next;
ListHead->next = p;
}
return ListHead;
}
void PrintList(LinkList ListHead)//实现的一个输出表的函数
{
if(ListHead == NULL)
cout<<"This is empty list"<<endl;
else
{
LinkedNode* p = ListHead;
while(p != NULL)
{
cout<<p->data<<" ";
p = p->next;
}
cout<<endl;
}
}
void RecReverseList(LinkedNode* pCur,LinkList& ListHead)//递归实现表的反转
{
if( (NULL == pCur) || (NULL == pCur->next) )
{
ListHead = pCur;
}
else
{
LinkedNode* pNext = pCur->next;
RecReverseList(pNext,ListHead);
pNext->next = pCur;
pCur->next= NULL;
}
}
void UnRecReverseList(LinkList& ListHead)//非递归实现表的反转
{
if(NULL == ListHead)
return ;
LinkedNode *pre,*cur,*nex;
pre = ListHead;
cur = pre->next;
while(cur)
{
nex = cur->next;
cur->next = pre;
pre = cur;
cur = nex;
}
ListHead->next= NULL;
ListHead = pre;
}
int main()
{
int arr[] = {1,2,3,4,5,6};
LinkedNode* list = CreateList(a);
PrintList(list);
LinkedNode* pTemp = list;
RecReverseList(pTemp,list);
PrintList(list);
UnRecReverseList(list);
PrintList(list);
return 0;
}
双向链表:先处理前向指针,然后处理后向指针。这些操作都只对当前节点(current),不涉及其它节点。
1.缓存前向指针
2.将后向指针赋值给前向指针
3.将缓存的前者指针,赋值给后向指针
4.当前节点指针移动到下一个待处理节点
#include <iostream>
typedef int DataType;//定义数据类型
typedef struct Node
{
DataType data;
Node *next; // 指向下一个节点
Node *prev; // 指向前一个节点
};
//对链表进行反转
void reverse(Node **head)
{
Node *temp = NULL;
Node *current = *head;
//交换每个节点的后向指针和前向指针
while (current != NULL)
{
temp = current->prev; //temp=1
current->prev = current->next; //3-->2
current->next = temp; //2-->1
current = current->prev; //3-->2-->1, current变为3,继续往后循环。
}
//修改头指针之前,先检测链表是否为空链表,或者只有一个节点的情况
if (temp != NULL)
*head = temp->prev;
}
void createDoubleList(Node** head, int newData)
{
//1. 分配新节点内存
Node* newNode = new Node;
//2. 赋值
newNode->data = newData;
//3. 将原始头节点做为新节点的后向指针,而前向指针置为NULL
newNode->next = (*head);
newNode->prev = NULL;
//4. 将原始头节点的前向指针置为新的节点
if ((*head) != NULL)
(*head)->prev = newNode;
//5. 将头指针置为新的节点
(*head) = newNode;
}
void printList(Node *head)
{
while (head != NULL)
{
std::cout<<" "<<head->data<<" ";
head = head->next;
}
std::cout << std::endl;
}
int main()
{
//初始化链表为:10<->8<->6<->4<->2<->0
int arr[]={0,2,4,6,8,10};
Node* head = NULL;
for(int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
createDoubleList(&head, arr[i]);
std::cout << "Original DLL is: ";
printList(head);
reverse(&head);
std::cout << "Reversed DLL is: ";
printList(head);
return 0;
}
“之”字形打印矩阵
【题目】 给定一个矩阵matrix,按照“之”字形的方式打印这个矩阵,例如:
1 2 3 4
5 6 7 8
9 10 11 12
“之”字形打印的结果为:1,2,5,9,6,3,4,7,10,11, 8,12
【要求】 额外空间复杂度为O(1)。
#include<iostream>
#include<string>
#include<queue>
#include<cstdlib>
#include<stdexcept>//标准异常库
using namespace std;
void printLevel(int *m[], int tR, int tC, int dR, int dC,bool f);
void printMatrixZigZag(int *matrix[],int row,int col)
{
int tR = 0,tC = 0,dR = 0,dC = 0;
int endR = row - 1;
int endC = col - 1;
bool fromUp = false;
while (tR != endR + 1)
{
printLevel(matrix, tR, tC, dR, dC, fromUp);
tR = tC == endC ? tR + 1 : tR;
tC = tC == endC ? tC : tC + 1;
dC = dR == endR ? dC + 1 : dC;
dR = dR == endR ? dR : dR + 1;
fromUp = !fromUp;
}
cout<<endl;
}
void printLevel(int *m[], int tR, int tC, int dR, int dC,bool f)
{
if (f)
{
while (tR != dR + 1)
{
cout<<m[tR++][tC--]<<" ";
}
}
else
{
while (dR != tR - 1)
{
cout<<m[dR--][dC++]<<" ";
}
}
}
int main()
{
int row,col;
cin>>row>>col;
int **matrix=(int **)malloc(sizeof(int)*row);
int *p[row+1];
for(int i=0;i<row;i++)
{
matrix[i]=(int *)malloc(sizeof(int)*col);
for(int j=0;j<col;j++)
{
cin>>matrix[i][j];
}
}
for(int i=0;i<row;i++){
p[i]=matrix[i];
}
printMatrixZigZag(p,row,col);
return 0;
}
在行列都排好序的矩阵中找数
【题目】 给定一个有N*M的整型矩阵matrix和一个整数K, matrix的每一行和每一列都是排好序的。实现一个函数,判断K 是否在matrix中。
例如:
0 1 2 5
2 3 4 7
4 4 4 8
5 7 7 9
如果K为7,返回true;如果K为6,返回false。
【要求】 时间复杂度为O(N+M),额外空间复杂度为O(1)。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
bool isContains(int *matrix[], int Row,int Col,int K) {
int row = 0;
int col = Col - 1;
while (row < Row && col > -1) {
if (matrix[row][col] == K) {
return true;
} else if (matrix[row][col] > K) {
col--;
} else {
row++;
}
}
return false;
}
int main() {
int row,col,K;
cin>>row>>col;
int **matrix=(int **)malloc(sizeof(int)*row);
int *p[col+1];
for(int i=0;i<row;i++)
{
matrix[i]=(int *)malloc(sizeof(int)*col);
for(int j=0;j<col;j++)
{
cin>>matrix[i][j];
}
}
for(int i=0;i<row;i++)
{
p[i]=matrix[i];
}
cin>>K;
cout<<(isContains(p, row,col,K)?"Yes":"No");
}
打印两个有序链表的公共部分
【题目】 给定两个有序链表的头指针head1和head2,打印两个 链表的公共部分。
#include <iostream>
#include <string>
using namespace std;
struct Node {
int value;
Node *next;
};
Node *add_Node(Node *head, int value) {
Node *new_Node = new Node();
new_Node -> value = value;
new_Node -> next = NULL;
Node *p_Node = new Node();
p_Node = head;
if(head == NULL)
head = new_Node;
else{
while(p_Node -> next != NULL) {
p_Node = p_Node -> next;
}
p_Node -> next = new_Node;
}
return head;
}
void print_common_part(Node *head1, Node *head2) {
while(head1 != NULL && head2 != NULL) {
if(head1 -> value < head2 -> value)
head1 = head1 -> next;
else if(head1 -> value > head2 -> value)
head2 = head2 -> next;
else {
cout << head1 -> value << ' ';
head1 = head1 -> next;
head2 = head2 -> next;
}
}
}
int main() {
Node *head1 = NULL;
Node *head2 = NULL;
string str, str_s;
cout << "please input the data of list1!" << endl;
getline(cin, str);
while(str.find(' ', 0) != string :: npos) {
head1 = add_Node(head1, atoi(str.substr(0, str.find(' ', 0)).c_str()));
str.erase(0, str.find(' ', 0) + 1);
}
head1 = add_Node(head1, atoi(str.c_str()));
cout << "please input the data of list2!" << endl;
getline(cin, str);
while(str.find(' ', 0) != string :: npos) {
head2 = add_Node(head2, atoi(str.substr(0, str.find(' ', 0)).c_str()));
str.erase(0, str.find(' ', 0) + 1);
}
head2 = add_Node(head2, atoi(str.c_str()));
cout << "the common part is: " << endl;
print_common_part(head1, head2);
return 0;
}
判断一个链表是否为回文结构
【题目】 给定一个链表的头节点head,请判断该链表是否为回文结构。
例如:
1->2->1,返回true。 1->2->2->1,返回true。
15->6->15,返回true。 1->2->3,返回false。
进阶: 如果链表长度为N,时间复杂度达到O(N),额外空间复杂 度达到O(1)。
#include <iostream>
#include <string>
#include<stack>
using namespace std;
struct node {
int value;
node *next;
};
node *add_node(node *head, int value) {
node *new_node = new node();
new_node -> value = value;
new_node -> next = NULL;
node *p_node = new node();
p_node = head;
if(head == NULL)
head = new_node;
else {
while(p_node -> next != NULL) {
p_node = p_node -> next;
}
p_node -> next = new_node;
}
return head;
}
// need n extra space
bool isPalindrome1(node *head) {
stack<node> s;
node *cur = head;
while (cur != NULL) {
s.push(*cur);
cur = cur->next;
}
while (head != NULL) {
if (head->value != s.top().value) {
return false;
}
head = head->next;
s.pop();
}
return true;
}
// need n/2 extra space
bool isPalindrome2(node *head) {
if (head == NULL || head->next == NULL) {
return true;
}
node *right = head->next;
node *cur = head;
while (cur->next != NULL && cur->next->next != NULL) {
right = right->next;
cur = cur->next->next;
}
stack<node> s;
while (right != NULL) {
s.push(*right);
right = right->next;
}
while (!s.empty()) {
if (head->value != s.top().value) {
return false;
}
head = head->next;
s.pop();
}
return true;
}
// need O(1) extra space
bool isPalindrome3(node *head) {
if (head == NULL || head->next == NULL) {
return true;
}
node *n1 = head;
node *n2 = head;
while (n2->next != NULL && n2->next->next != NULL) { // find mid node
n1 = n1->next; // n1 -> mid
n2 = n2->next->next; // n2 -> end
}
n2 = n1->next; // n2 -> right part first node
n1->next = NULL; // mid.next -> null
node *n3 = NULL;
while (n2 != NULL) { // right part convert
n3 = n2->next; // n3 -> save next node
n2->next = n1; // next of right node convert
n1 = n2; // n1 move
n2 = n3; // n2 move
}
n3 = n1; // n3 -> save last node
n2 = head;// n2 -> left first node
bool res = true;
while (n1 != NULL && n2 != NULL) { // check palindrome
if (n1->value != n2->value) {
res = false;
break;
}
n1 = n1->next; // left to mid
n2 = n2->next; // right to mid
}
n1 = n3->next;
n3->next = NULL;
while (n1 != NULL) { // recover list
n2 = n1->next;
n1->next = n3;
n3 = n1;
n1 = n2;
}
return res;
}
void printLinkedList(node *n1) {
cout<<"Linked List: ";
while (n1!= NULL) {
cout<<n1->value << " ";
n1 = n1->next;
}
cout<<endl;
}
int main() {
node *list=NULL;
list=add_node(list,1);
list=add_node(list,2);
list=add_node(list,2);
list=add_node(list,1);
printLinkedList(list);
cout<<isPalindrome1(list) <<" | ";
cout<<isPalindrome2(list) << " | ";
cout<<isPalindrome3(list) <<" | "<<endl;
printLinkedList(list);
}
将单向链表按某值划分成左边小、中间相等、右边大的形式
【题目】 给定一个单向链表的头节点head,节点的值类型是整型,再给定一个 整数pivot。实现一个调整链表的函数,将链表调整为左部分都是值小于 pivot 的节点,中间部分都是值等于pivot的节点,右部分都是值大于 pivot的节点。 除这个要求外,对调整后的节点顺序没有更多的要求。
进阶: 在原问题的要求之上再增加如下两个要求。 在左、中、右三个部分的内部也做顺序要求,要求每部分里的节点从左 到右的 顺序与原链表中节点的先后次序一致.
【要求】如果链表长度为N,时间复杂度请达到O(N),额外空间复杂度请达到O(1)。
有问题
#include <iostream>
#include <string>
#include<stack>
#include<cstdlib>
using namespace std;
struct Node
{
int value;
Node *next;
};
void arrPartition(Node *nodeArr[], int row,int pivot);
void swap_Node(Node *nodeArr[], int a, int b);
Node *add_node(Node *head, int value)
{
Node *new_node = new Node();
new_node -> value = value;
new_node -> next = NULL;
Node *p_node = new Node();
p_node = head;
if(head == NULL)
head = new_node;
else
{
while(p_node -> next != NULL)
{
p_node = p_node -> next;
}
p_node -> next = new_node;
}
return head;
}
Node *listPartition1(Node *head, int pivot)
{
if (head == NULL)
{
return head;
}
Node *cur = head;
int i = 0;
while (cur != NULL)
{
i++;
cur = cur->next;
}
int row=i;
Node *nodeArr[row+1] ;
cur = head;
for (i = 0; i != sizeof(nodeArr)/sizeof(nodeArr[0]); i++)
{
nodeArr[i] = cur;
cur = cur->next;
}
arrPartition(nodeArr, row ,pivot);
for (i = 1; i != sizeof(nodeArr)/sizeof(nodeArr[0]); i++)
{
nodeArr[i - 1]->next = nodeArr[i];
}
nodeArr[i - 1]->next = NULL;
return nodeArr[0];
}
void arrPartition(Node *nodeArr[],int row, int pivot)
{
int small = -1;
int big = row;
int index = 0;
while (index != big)
{
if (nodeArr[index]->value < pivot)
{
swap_Node(nodeArr, ++small, index++);
}
else if (nodeArr[index]->value == pivot)
{
index++;
}
else
{
swap_Node(nodeArr, --big, index);
}
}
}
void swap_Node(Node *nodeArr[], int a, int b)
{
Node *tmp = nodeArr[a];
nodeArr[a] = nodeArr[b];
nodeArr[b] = tmp;
}
Node *listPartition2(Node *head, int pivot)
{
Node *sH = NULL; // small head
Node *sT = NULL; // small tail
Node *eH = NULL; // equal head
Node *eT = NULL; // equal tail
Node *bH = NULL; // big head
Node *bT = NULL; // big tail
Node *next = NULL; // save next node
// every node distributed to three lists
while (head != NULL)
{
next = head->next;
head->next = NULL;
if (head->value < pivot)
{
if (sH == NULL)
{
sH = head;
sT = head;
}
else
{
sT->next = head;
sT = head;
}
}
else if (head->value == pivot)
{
if (eH == NULL)
{
eH = head;
eT = head;
}
else
{
eT->next = head;
eT = head;
}
}
else
{
if (bH == NULL)
{
bH = head;
bT = head;
}
else
{
bT->next = head;
bT = head;
}
}
head = next;
}
// small and equal reconnect
if (sT != NULL)
{
sT->next = eH;
eT = eT == NULL ? sT : eT;
}
// all reconnect
if (eT != NULL)
{
eT->next = bH;
}
return sH != NULL ? sH : eH != NULL ? eH : bH;
}
void printLinkedList(Node *node)
{
cout<<"Linked List: ";
while (node != NULL)
{
cout<<node->value << " ";
node = node->next;
}
cout<<endl;
}
int main()
{
Node *listHead1=NULL,*listHead2=NULL;
listHead1=add_node(listHead1,6);
listHead1=add_node(listHead1,9);
listHead1=add_node(listHead1,5);
listHead1=add_node(listHead1,4);
listHead1=add_node(listHead1,1);
listHead1=add_node(listHead1,2);
listHead1=add_node(listHead1,1);
listHead1=add_node(listHead1,5);
listHead2=add_node(listHead2,6);
listHead2=add_node(listHead2,9);
listHead2=add_node(listHead2,5);
listHead2=add_node(listHead2,4);
listHead2=add_node(listHead2,1);
listHead2=add_node(listHead2,2);
listHead2=add_node(listHead2,1);
listHead2=add_node(listHead2,5);
printLinkedList(listHead1);
printLinkedList(listHead2);
//listHead2 = listPartition1(listHead2, 4);
listHead1 = listPartition2(listHead1, 5);
printLinkedList(listHead1);
printLinkedList(listHead2);
return 0;
}
复制含有随机指针节点的链表
【题目】 一种特殊的链表节点类描述如下:
struct Node
{
int value;
Node *next;
Node *rand;
};
Node类中的value是节点值,next指针和正常单链表中next指针的意义一样,都指向下一个节点,rand指针是Node类中新增的指针,这个指针可能指向链表中的任意一个节点,也可能指向null。
给定一个由Node节点类型组成的无环单链表的头节点head,请实现一个函数完成这个链表中所有结构的复制,并返回复制的新链表的头节点。 进阶:不使用额外的数据结构,只用有限几个变量,且在时间复杂度为O(N)内完成原问题要实现的函数。
/*
*文件名:listWithRand_copy.cpp
*作者:
*摘要:复制含有随机指针节点的链表
*/
#include <iostream>
#include <hash_map>
using namespace std;
using namespace __gnu_cxx;
struct Node
{
int value;
Node *next;
Node *rand;
};
//使用hash_map所需要的hash函数
struct hash_Node
{
size_t operator() (const Node &node) const
{
return node.value;
}
};
//使用hash_map所需要的比较函数
struct compare_Node
{
bool operator() (const Node &n1,const Node &n2) const
{
return n1.value == n2.value && n1.next == n2.next && n1.rand == n2.rand;
}
};
//使用hash_map解决问题
Node* copyListWithRand1(Node *head)
{
hash_map<Node,Node,hash_Node,compare_Node> map;
Node *cur = head;
while(NULL != cur)
{
Node *ptr = new Node;
ptr->value = cur->value;
ptr->next = NULL;
ptr->rand = NULL;
map[*cur] = *ptr; //一一对应的关系
cur = cur->next;
}
cur = head;
while(NULL != cur)
{
map[*cur].next = cur->next;
map[*cur].rand = cur->rand;
cur = cur->next;
}
return &map[*head];
}
Node* copyListWithRand2(Node *head)
{
if(NULL == head)
return NULL;
Node *cur = head;
Node *next = NULL;
while(NULL != cur)
{
next = new Node;
next->value = cur->value;
next->next = cur->next;
next->rand = NULL;
cur->next = next;
cur = next->next;
}
cur = head;
Node *curCopy = NULL;
while(NULL != cur) //复制rand
{
next = cur->next->next;
curCopy = cur->next;
curCopy->rand = NULL != cur->rand ? cur->rand->next : NULL;
cur = next;
}
Node *res = head->next;
cur = head;
while(NULL != cur)
{
next = cur->next->next;
curCopy = cur->next;
cur->next = next;
curCopy->next = NULL != next ? next->next : NULL;
cur = next;
}
return res;
}
void printListWithRand(Node *head)
{
while(NULL != head)
{
if(NULL != head->rand)
cout << head->value << " rand is: " << head->rand->value << endl;
else
cout << head->value << " rand is: NULL " << endl;
if(NULL != head->next)
cout << head->value << " next is: " << head->next->value << endl;
else
cout << head->value << " next is: NULL " << endl;
head = head->next;
}
}
int main()
{
Node *head = NULL;
Node *ptr = NULL;
for(int i =0;i<4;i++)//构造链表
{
if(NULL == head)
{
head = new Node;
head->value = i;
head->next = NULL;
head->rand = NULL;
ptr = head;
continue;
}
ptr->next = new Node;
ptr->rand = ptr->next;
ptr = ptr->next;
ptr->value = i;
ptr->next = NULL;
ptr->rand = NULL;
}
cout << "before copy:" << endl;
printListWithRand(head);
cout << "Using hash_map to copy:" << endl;
ptr = copyListWithRand1(head);
printListWithRand(ptr);
cout << "Using advanced algorithm to copy:" << endl;
ptr = copyListWithRand2(head);
printListWithRand(ptr);
return 0;
}
两个单链表相交的一系列问题
【题目】 在本题中,单链表可能有环,也可能无环。给定两个单链表的头节点head1和head2,这两个链表可能相交,也可能不相交。
请实现一个函数,如果两个链表相交,请返回相交的第一个节点;如果不相交,返回null 即可。
要求:如果链表1的长度为N,链表2的长度为M,时间复杂度请达到 O(N+M),额外空间复杂度请达到O(1)。
#include <iostream>
using namespace std;
struct Node
{
int value;
Node *next;
};
Node *getLoopNode(Node *head);
Node *noLoop(Node *head1, Node *head2);
Node *bothLoop(Node *head1, Node *loop1, Node *head2, Node *loop2);
Node *getIntersectNode(Node *head1, Node *head2);
Node *add_node(Node *head, int value)
{
Node *new_node = new Node();
new_node -> value = value;
new_node -> next = NULL;
Node *p_node = new Node();
p_node = head;
if(head == NULL)
head = new_node;
else
{
while(p_node -> next != NULL)
{
p_node = p_node -> next;
}
p_node -> next = new_node;
}
return head;
}
Node *getIntersectNode(Node *head1, Node *head2)
{
if (head1 == NULL || head2 == NULL)
{
return NULL;
}
Node *loop1 = getLoopNode(head1);
Node *loop2 = getLoopNode(head2);
if (loop1 == NULL && loop2 == NULL)
{
return noLoop(head1, head2);
}
if (loop1 != NULL && loop2 != NULL)
{
return bothLoop(head1, loop1, head2, loop2);
}
return NULL;
}
/**
*
* 获取环的入口节点
*/
Node *getLoopNode(Node *head)
{
if (head == NULL || head->next == NULL || head->next->next == NULL)
{
return NULL;
}
Node *n1 = head->next; // n1 -> slow
Node *n2 = head->next->next; // n2 -> fast
while (n1 != n2)
{
if (n2->next == NULL || n2->next->next == NULL)
{
return NULL;
}
n2 = n2->next->next;
n1 = n1->next;
}
n2 = head; // n2 -> walk again from head
while (n1 != n2)
{
n1 = n1->next;
n2 = n2->next;
}
return n1;
}
/**
* 两个无环链表
*
*/
Node *noLoop(Node *head1, Node *head2)
{
if (head1 == NULL || head2 == NULL)
{
return NULL;
}
Node *cur1 = head1;
Node *cur2 = head2;
int n = 0;
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 = (n>0?n:-n);
while (n != 0)
{
n--;
cur1 = cur1->next;
}
while (cur1 != cur2)
{
cur1 = cur1->next;
cur2 = cur2->next;
}
return cur1;
}
/**
* 两个有环链表
* @param head1 第一个链表的头节点
* @param loop1 第一个链表的入环节点
* @param head2 第二个链表的头节点
* @param loop2 第二个链表的入环节点
* @return Node 两个链表第一次相交的节点
*/
Node *bothLoop(Node *head1, Node *loop1, Node *head2, Node *loop2)
{
Node *cur1 = NULL;
Node *cur2 = NULL;
if (loop1 == loop2)
{
cur1 = head1;
cur2 = head2;
int n = 0;
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 = (n>0?n:-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;
}
}
int main()
{
// 1->2->3->4->5->6->7->null
Node *head1;
head1=add_node(head1,1);
head1=add_node(head1,2);
head1=add_node(head1,3);
head1=add_node(head1,4);
head1=add_node(head1,5);
head1=add_node(head1,6);
head1=add_node(head1,7);
// 0->9->8->6->7->null
Node *head2;
head2=add_node(head2,0);
head2=add_node(head2,9);
head2=add_node(head2,8);
head2->next->next->next = head1->next->next->next->next->next; // 8->6
cout<<(getIntersectNode(head1, head2)->value);
// 1->2->3->4->5->6->7->4->->->
Node *head3;
head3=add_node(head3,1);
head3=add_node(head3,2);
head3=add_node(head3,3);
head3=add_node(head3,4);
head3=add_node(head3,6);
head3=add_node(head3,7);
head3->next->next->next->next->next->next = head3->next->next->next; // 7->4
// 0->9->8->2->->->
Node *head4;
head4=add_node(head4,0);
head4=add_node(head4,9);
head4=add_node(head4,8);
head4->next->next->next = head3->next; // 8->2
cout<<(getIntersectNode(head3, head4)->value);
// 0->9->8->6->4->5->6->->
Node *head5;
head5=add_node(head5,0);
head5=add_node(head5,9);
head5=add_node(head5,8);
head5->next->next->next = head3->next->next->next->next->next; // 8->6
cout<<(getIntersectNode(head3, head5)->value);
}