链表:有环单向链表

14 篇文章 0 订阅
  • 定义
struct ListNode{
	int value;
	ListNode* next;
	ListNode(int v,ListNode* nt):value(v),next(nt){}
	ListNode(int v):ListNode(v,nullptr){}
	ListNode():ListNode(0){}
	virtual ~ListNode()=default;
};
  • 问题
    1.如何判断一个链表有环
    2.环的长度是多少
    3.环的结点位置在哪里
    4.链表的长度是多少
    5.如何变成无环单向链表
    关于这些问题可以定义一个结构体
struct RingListInfo {
	bool has_ring = false;
	size_t length = 0;
	size_t ring_length = 0;
	ListNode* ring_node = nullptr;
	ListNode* tail = nullptr;
	ListNode* head = nullptr;
	RingListInfo()=default;
};

使用map

#include <map>
void list_info(ListNode* head,RingListInfo& info){
	info.head = head;
	if(!head){return;}
	std::map<ListNode*,int> map_;
	int idx = 0;
	ListNode* before = nullptr; // 记录每次迭代的前一个结点
	for(auto p=head;p->next;p=p->next){
		if(map_.find(p) == map_.end()){
			set_.insert({p,idx++});
		}else{ // p点是环的结点
			info.has_ring = true;
			info.ring_node = p;
			info.length= map_.size();
			info.ring_length = info.length - map_[p]
			info.tail = before;
			return;
		}
		before = p;
	}
}

空间复杂度 O(n) ,时间复杂度O(nlogn)

使用快慢指针

void list_info(ListNode* head,RingListInfo& info){
	info.head = head;
	if(!head){return;}
	auto slow = head;
	auto fast = head;
	int ct_slow = 0; // 记录慢指针的步数
	int ct_fast = 0; // 记录快指针的步数
	while(true){
		if(!fast){break;}
		slow = slow->next;
		ct_slow += 1;
		fast = fast->next;
		ct_fast += 1;
		if(!fast){break;}
		fast = fast->next;
		ct_fast += 1;
		if(slow == fast){ // 快慢指针的相遇点
			info.has_ring = true;
			break;
		}
	}
	info.ring_length = ct_slow ; // head 到相遇点的距离就是环的长度!
	if(!info.has_ring){return;}
	// meet_node => 相遇点
	// head到ring_node 的距离等于meet_node到ring_node的距离
	auto left = head;
	auto right = slow;
	int ct = 0;
	while(left != right){
		ct += 1;
		left=left->next;
		right=right->next;
	}
	info.ring_node = left;
	info.length = info.ring_length + ct;
}
  • 解析

设 头指针head,最后一个结点指针tail
环结点为 ring_node ,快慢指针的相遇点为 meet_node
list上两个指针的距离 <p1,p2> ,就是重复p1 = p1->next直到p1 == p2时候的重复次数
环长度ring_length,链表长度length<head,ring_node> = length - ring_length;

如果list有环
首先 快慢指针一定会相遇,相遇位置一定是在在环上!
如果单纯想知道环的长度,让慢指针再走一圈就知道了,ring_length = <meet_node,meet_node>

在些需要发现和证明一件事,就是 <head,meet_node> == <meet_node,meet_node>;
因为 speed(fast) = 2 * speed(slow) ,当slow和fast现时从head出发,slow到达meet_node时,fast走的路途就是
<head,meet_node> + <meet_node,meet_node> = 2 * <head,meet_node>
即 <meet_node,meet_node> = <head,meet_node> = ring_length
自然 设计一个slow_left从meet_node出发,slow_right从head出发,slow_left和slow_right就会在ring_node相遇.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tadus_zeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值