Leetcode学习之链表(2)

开宗明义:本系列基于小象学院林沐老师课程《面试算法 LeetCode 刷题班》,刷题小白,旨在理解和交流,重在记录,望各位大牛指点!


Leetcode学习之链表(2)



1、链表求交点 LeetCode 160

题目来源: L e e t C o d e   160.   I n t e r s e c t i o n   o f   T w o   L i n k e d   L i s t LeetCode \ 160.\ Intersection \ of \ Two \ Linked \ List LeetCode 160. Intersection of Two Linked List
题目描述:已知链表A的头节点指针 h e a d   A head \ A head A,链表B的头节点指针 h e a d   B head \ B head B,两个链表相交,求两链表交点对应的节点。
题目要求:

  1. 如果两个链表没有交点,则返回 NULL
  2. 在求交点的过程中,不可以破坏链表的结构或者修改结构的数据域
  3. 可以确保传入的链表A与链表B没有任何环
  4. 实现算法尽可能使时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( 1 ) O(1) O(1)

要求描述:在这里插入图片描述

1.1 set的使用

S T L STL STL里面的 s e t set set,集合——每个元素最多只出现一次,并且元素已经从小到大排好序。
c + + c++ c++使用时包含 # i n c l u d e   &lt; s e t &gt; \#include \ &lt;set&gt; #include <set>

小试牛刀:判断两组数组中是否有相同元素, O ( n ) O(n) O(n)或者 O ( n l o g n ) O(nlogn) O(nlogn)的复杂度
测试代码:

#include <set>

using namespace std;

int main()
{
	set<int> test_set;
	const int A_LEN = 7;  //测试数组A与B的长度
	const int B_LEN = 8;
	//a,b中有重复元素
	int a[A_LEN] = {5,1,4,8,10,1,3};
	int b[B_LEN] = {2,7,6,3,1,6,0,1};

	for (int i = 0; i < A_LEN; i++)
	{
		test_set.insert(a[i]);//将数组a元素插入set中
	}
	//检查数组b中元素是否存在a中
	for (int i = 0; i < B_LEN; i++)
	{
		if (test_set.find(b[i]) != test_set.end())
			//用来查找set中某个元素出现的位置。如果找到,就返回这个元素的迭代器,如果这个元素不存在,则返回 s.end() 。
			//(最后一个元素的下一个位置,s为set的变量名)
		{
			printf("b[%d]=%d in array A.\n",i,b[i]);
		}
	}
	system("pause");
	return 0;
}

效果图:
在这里插入图片描述
总结:
1.begin():返回set容器的第一个迭代器
2.end():返回set容器的最后一个迭代器
3.clear():删除set容器中的所有的元素
4.empty():判断set容器是否为空
5.max_size():返回set容器可能包含的元素最大个数
6.size():返回当前set容器中的元素个数
7.rbegin:返回的值和end()相同
8.rend():返回的值和rbegin()相同
9..insert(a):插入元素
10..count():用来查找set中某个元素出现的次数。这个函数在set并不是很实用,因为一个键值在set只可能出现0或1次,这样就变成了判断某一键值是否在set出现过了
11..find():用来查找set中某个元素出现的位置。如果找到,就返回这个元素的迭代器,如果这个元素不存在,则返回 s.end() 。 (最后一个元素的下一个位置,s为set的变量名)


1.2 思路①

思路①使用 s e t set set求交集, O ( n ) O(n) O(n)或者 O ( n l o g n ) O(nlogn) O(nlogn)的复杂度
1、遍历链表 A A A,将 A A A中节点对应的指针(地址),插入 s e t set set
2、遍历链表 B B B,将 B B B中节点对应的指针(地址),在 s e t set set中查找,在 s e t set set中的第一个节点地址,即两个链表的交点
在这里插入图片描述测试代码:
在这里插入图片描述

#include <stdio.h>
#include <set>
using namespace std;

struct ListNode {
	int val;
	ListNode *next;
	ListNode(int x) :val(x), next(NULL) {}
};

class Solution {
public://A,B的头节点指针
	ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
		set<ListNode *> node_set;//设置查找集合node_set
		while (headA)
		{
			node_set.insert(headA);//将链表A中的节点插入node_set
			headA = headA->next;//遍历链表A
		}
		while (headB)
		{
			if (node_set.find(headB) != node_set.end())
			{
				return headB;
			}
			headB = headB->next;//遍历链表B
		}
		return NULL;
	}
};

int main()
{
	ListNode a1(1), a2(2), b1(3), b2(4), b3(5), c1(6), c2(7), c3(8);
	a1.next = &a2;
	a2.next = &c1;
	c1.next = &c2;
	c2.next = &c3;
	b1.next = &b2;
	b2.next = &b3;
	b3.next = &c1;
	Solution solve;
	ListNode *result = solve.getIntersectionNode(&a1, &b1);
	printf("%d\n",result->val);
	system("pause");
	return 0;
}

效果图:
在这里插入图片描述


1.3 思路②

空间复杂度 O ( 1 ) O(1) O(1)
思路②

  1. 计算 h e a d A headA headA链表长度,计算 h e a d B headB headB链表长度,得出较长的链表多出的长度;
  2. 将较长链表的指针移动到和较短链表指针对齐的位置;
  3. h e a d A headA headA h e a d B headB headB同时移动,当两指针指向同一个节点时,即找到了。

cesh在这里插入图片描述测试代码:

#include <stdio.h>
#include <set>
using namespace std;

struct ListNode {
	int val;
	ListNode *next;
	ListNode(int x) :val(x), next(NULL) {}
};

//返回链表长度
int get_list_length(ListNode *head)
{
	int len = 0;
	while (head)
	{
		len++;
		head = head->next;
	}
	return len;
}

ListNode *forward_long_list(int long_len,int short_len,ListNode *head) 
{
	int data = long_len - short_len;
	while (head && data) {
		head = head->next;
		data--;
	}
	return head;
}

class Solution {
public://A,B的头节点指针
	ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
		int list_A_len = get_list_length(headA);
		int list_B_len = get_list_length(headB);//求链表A、B长度
		if (list_A_len > list_B_len) {
			headA = forward_long_list(list_A_len, list_B_len, headA);//如果链表A长,移动A到对应位置
		}
		else{
			headB = forward_long_list(list_B_len, list_A_len, headB);
		}
		while (headA && headB)
		{
			if (headA == headB) {  //当两指针指向同一个节点时候,说明找到了
				return headA;
			}
			headA = headA->next;
			headB = headB->next;
		}
		return NULL;
	}
};

int main()
{
	ListNode a1(1), a2(2), b1(3), b2(4), b3(5), c1(6), c2(7), c3(8);
	a1.next = &a2;
	a2.next = &c1;
	c1.next = &c2;
	c2.next = &c3;
	b1.next = &b2;
	b2.next = &b3;
	b3.next = &c1;
	Solution solve;
	ListNode *result = solve.getIntersectionNode(&a1, &b1);
	printf("%d\n",result->val);
	system("pause");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值