LeetCode:返回链表入环的第一个节点

/*
leetCode142
题目描述:给定一个链表,返回链表开始入环的第一个节点.
如果链表无环,则返回null.为了表示给定链表中的环,我们使用整形pos来
表示链表尾连接到链表中的位置(索引从0开始).如果pos是-1,则在该链
表中没有环.注意,pos仅仅是用于标识环的情况,并不会作为参数传递到函数中.
说明:不允许修改给定的链表。

示例 1:
输入:head=[3,2,0,4],pos=1
输出:返回索引为1的链表节点
解释:链表中有一个环,其尾部连接到第二个节点;

示例 2:
输入:head=[1,2],pos=0
输出:返回索引为0的链表节点
解释:链表中有一个环其尾部连接到第一位节点;

示例 3:
输入:head=[1],pos=-1
输出:返回null
解释:链表中没有环;

解题思路:
利用双指针,一个慢指针S、一个快指针F(2S),设置入环前距离为a,慢指针
入环后走过的距离为b,环剩余距离为c,其中b+c代表一个环.
首次相遇:
(1)慢指针走过的路程:S=a+b;
(2)快指针走过的路程:F=a+n(b+c)+b,其中n>=1,快指针起码在环中走
了一圈以上才可能相遇;
(3)快指针走二步,慢指针走一步,即F=2S;
(4)因此2(a+b)=a+n(b+c)+b,所以a=(n-1)(b+c)+c;
(5)其中n为快指针绕的圈数,当n=1,a=c;当n=2,a=一圈+c;当n=3,
a=两圈+c....所以c为入环点,就是所求的索引点;
*/

Go语言实现 

package main

import "fmt"

//创建节点结构/类型
type Node struct{
	Data interface{}
	Next *Node
}

//创建链表结构
type List struct{
	Head *Node
	Size int   //头节点不作为链表长度
}

//设计接口
type Method interface {
	Insert(i int,v interface{})
	IsNull() bool
	GetSize() int
	Print()
	SetCycle(n int)
	detectCycle() interface{}
}

//创建节点
func CreateNode(v interface{} ) *Node{
	return &Node{v,nil}
}

//创建空链表
func CreateList() *List{
	return &List{CreateNode(nil),0}
}

//基于Method接口实现链表结构体
//在i处插入节点
func (list *List) Insert(i int,v interface{}){
	s:=CreateNode(v)
	pre:=list.Head //头节点
	for count:=0;count<=i;count++{
		if count==i-1{
			s.Next=pre.Next
			pre.Next=s
			list.Size++  //前插法
		}
		pre=pre.Next
	}
}

//判读是否为空
func (list *List) IsNull() bool{
	pre:=list.Head.Next
	if pre==nil{
		return true
	}
	return false
}

//返回链表长度
func (list *List) GetSize() int{
	return list.Size
}

//设计链表打印输出
func (list *List)Print(){
	pre:=list.Head.Next
	fmt.Println("链表:")
	for i:=1;i<=list.Size;i++{
		fmt.Printf("%v -> ", pre.Data)
		pre=pre.Next
	}
}

//设置环入口的索引点
func (list* List)SetCycle(n int){
	temp,last:=list.Head.Next,list.Head.Next
	for i:=1;i<n;i++{
		temp=temp.Next
	}
	for i:=1;i<list.Size;i++{
		last=last.Next
	}
	/*尾部节点指向索引节点*/
	last.Next=temp
}
func (list* List)detectCycle()interface{}{
	fast,slow:=list.Head.Next,list.Head.Next

	/*首次相遇时,slow的位置*/
	for fast!=nil&&fast.Next!=nil{
		fast=fast.Next.Next
		slow=slow.Next
		if slow==fast{
			break
		}
	}

	/*如果快指针走到尽头,没环*/
	for fast==nil||fast.Next==nil{
		return -1
	}

	/*快指针重新出发,相遇位置就是入口的位置*/
	fast=list.Head.Next
	for fast!=slow{
		fast=fast.Next
		slow=slow.Next
	}
	return slow.Data
}

func main() {
	fmt.Println("链表开始入环的第一个节点")
	list := CreateList()
	var m Method //或者var m Method=CreateList()
	m = list
	m.Insert(1, 3)
	m.Insert(2, 7)
	m.Insert(3, 8)
	m.Insert(4, 10)
	m.SetCycle(3)
	m.Print()
	fmt.Println(m.detectCycle())
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

路上的追梦人

您的鼓励就是我最大的动力

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

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

打赏作者

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

抵扣说明:

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

余额充值