链表追赶问题

本文详细介绍了如何使用Java实现链表的倒数第K个节点查找、判断两个链表是否相交及判断相交点的方法,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看过July的链表追赶问题后,想总结并且用java代码实现下:

问题1 : 求链表倒数第K个

	class ListNode{
		int data;
		ListNode next;
		public ListNode(){}
		public ListNode(int data){
			this.data = data;
		}
		public int getData() {
			return data;
		}
		public void setData(int data) {
			this.data = data;
		}
		public ListNode getNext() {
			return next;
		}
		public void setNext(ListNode next) {
			this.next = next;
		}
	}
	
	ListNode head, p, q;
	ListNode pOne, pTwo;
	
	ListNode fun(ListNode head, int k){
		pOne = pTwo = head;
		for(;k>0 && pTwo!=null;k--){
			pTwo = pTwo.next;
		}
		if(k>0) return null;
		while(pTwo!=null){
			pOne = pOne.next;
			pTwo = pTwo.next;
		}
		return  pOne;
	}

问题2 : 编程判断两个链表是否相交

思路和大部分文字都是从July的博客上面来的:

1. 暴力破解直接遍历,额

2.  相交了就代表有相同的节点,判断相同,应该想到hash,用空间换取时间。

   针对第一个链表以内存地址为内容构造hash表,遍历第二个链表,如果能找到,说明有相同节点,时间复杂度O(length(h1)+length(h2)),但是牺牲了空间。

    由于空间花费太大,所以个人觉得第2点一般是没有太大用处

3. 如果两个没有环的节点相交与某一节点,这个节点之后的所有节点都是两个链表共有的,所以只要判断两个链表的尾指针是否相等。时间复杂度与上面一样,但是空间是O(1)


由于解法3是面对无环,有环的时候怎么办?详情参见July的博客,这里只是贴出自己的java实现的地方:

判断是否有环,同时生成环中的一点,也就是相遇点,如果无环,生成链表的尾指针。

    static boolean isCircle(ListNode head, ListNodeClass LNC){
        ListNode fast = head.getNext();
        ListNode slow = head;
        
        // 暂时不知道是否有环,如果无环,fast和slow有一个会走到尾节点
        // 如果有环 fast和slow会相遇,所以两种情况他们都会跳出循环
        while(fast!=slow && fast.hasNext() && slow.hasNext()){
            if(fast.hasNext()){
                // fast先前进一步
                fast =  fast.getNext();
            }
            // 这个时候fast的next是null
            if(!fast.hasNext()){
                // 得到了尾指针
                LNC.lastNode = fast; 
            }
            // 一般情况下应该是fast比slow更快到达尾
            if(!slow.hasNext()){
                LNC.lastNode = slow;
            }
            
            if(fast.hasNext())
                fast=fast.getNext();
            if(slow.hasNext())
                slow = slow.getNext();
        }
        
        // fast slow 不是尾节点(环也没有尾节点)而且他们相遇了~~~
        if( fast==slow && fast.hasNext() && slow.hasNext()){
            LNC.circleNode = fast;//相遇点
            return true;
        }
        else{
            return false;//到达了尾节点,无环
        }
    }
    
    class ListNodeClass{
        public ListNode circleNode = null;
        public ListNode lastNode =null;
    }

接下来是 综合判断代码:

    boolean detect(ListNode head1 , ListNode head2){
        ListNodeClass LNC1 = new ListNodeClass();
        ListNodeClass LNC2 = new ListNodeClass();
        
        boolean isCircle1 = isCircle(head1,LNC1);
        boolean isCircle2 = isCircle(head2,LNC2);
        
        System.out.println("isCircle1: "+isCircle1);
        System.out.println("isCircle2: "+isCircle2);
        
        
        if(isCircle1!=isCircle2)
            return false;
        else if(!isCircle1 && !isCircle2)
            // 无环 ,比较尾节点
            return LNC1.lastNode == LNC2.lastNode;
        else{
            //判断同一个,两个带环链表是同一个链表
            if(LNC1.circleNode == LNC2.circleNode)
                return true;
            // 从其中一个相遇点出发
            ListNode tempNode = LNC1.circleNode.getNext();
            // 跳出循环条件是 走了一圈
            while(tempNode != LNC1.circleNode){
                //碰到了 circleNode2就是说在环内
                System.out.println("碰到了 circleNode2就是说在环内");
                if(tempNode == LNC2.circleNode)
                {
                    System.out.println("tempNode == LNC2.circleNode");
                    return true;
                }
                tempNode = tempNode.getNext();
            }
            return false;
        }
    }

全部的JAVA代码:

public class myLinkedList {
	public static void main(String[] args) {
		int[] arr = new int[]{1,2,3,4,5,6,7,8,9,10};
		myLinkedList myLinkedListObj = new myLinkedList();
		ListNode headNode = myLinkedListObj.buildList(arr);
		ListNode headCirNode = myLinkedListObj.buildCirList(arr,arr.length/2);

		ListNode tempNode = headCirNode;
		ListNode temp=null;

		System.out.println(myLinkedListObj.detect(headCirNode, headCirNode));
		System.out.println(myLinkedListObj.fun(headNode, 3).getData());
	}


	//   构造无环链表
	ListNode buildList(int[] arr){
		ListNode first = new ListNode();
		ListNode pNode = first;
		for(int da : arr){
			ListNode node = new ListNode(da);
			pNode.setNext(node);
			pNode = node;
		}
		return first;
	}

	// 构造有环链表
	ListNode buildCirList(int[] arr,int cir){
		int lengthOfArr = arr.length;
		int beginCir = cir;
		ListNode first = new ListNode();
		ListNode pNode = first;
		ListNode pNodeCir;

		for(int i=0;i<beginCir;i++){
			ListNode node = new ListNode(arr[i]);
			pNode.setNext(node);
			pNode = node;
		}

		// 此时的pNode是环首
		pNodeCir = pNode;
		for(int i=beginCir;i<lengthOfArr;i++){
			ListNode node = new ListNode(arr[i]);
			pNode.setNext(node);
			node.setNext(pNodeCir);
			pNode = node;
		}

		return first;
	}

	class ListNode{
		int data;
		ListNode next;
		public ListNode(){}
		public ListNode(int data){
			this.data = data;
		}
		public int getData() {
			return data;
		}
		public void setData(int data) {
			this.data = data;
		}
		public ListNode getNext() {
			return next;
		}
		public void setNext(ListNode next) {
			this.next = next;
		}
		public boolean hasNext(){
			return next==null?false:true;
		}
	}

	//	ListNode head, p, q;
	ListNode pOne, pTwo;

	ListNode fun(ListNode head, int k){
		pOne = pTwo = head;
		for(;k>0 && pTwo!=null;k--){
			pTwo = pTwo.next;
		}
		if(k>0) return null;
		while(pTwo!=null){
			pOne = pOne.next;
			pTwo = pTwo.next;
		}
		return  pOne;
	}

	static boolean isCircle(ListNode head, ListNodeClass LNC){
		ListNode fast = head.getNext();
		ListNode slow = head;

		// 暂时不知道是否有环,如果无环,fast和slow有一个会走到尾节点
		// 如果有环 fast和slow会相遇,所以两种情况他们都会跳出循环
		while(fast!=slow && fast.hasNext() && slow.hasNext()){
			if(fast.hasNext()){
				// fast先前进一步
				fast =  fast.getNext();
			}
			// 这个时候fast的next是null
			if(!fast.hasNext()){
				// 得到了尾指针
				LNC.lastNode = fast; 
			}
			// 一般情况下应该是fast比slow更快到达尾
			if(!slow.hasNext()){
				LNC.lastNode = slow;
			}

			if(fast.hasNext())
				fast=fast.getNext();
			if(slow.hasNext())
				slow = slow.getNext();
		}

		// fast slow 不是尾节点(环也没有尾节点)而且他们相遇了~~~
		if( fast==slow && fast.hasNext() && slow.hasNext()){
			LNC.circleNode = fast;//相遇点
			return true;
		}
		else{
			return false;//到达了尾节点,无环
		}
	}

	class ListNodeClass{
		public ListNode circleNode = null;
		public ListNode lastNode =null;
	}

	boolean detect(ListNode head1 , ListNode head2){
		ListNodeClass LNC1 = new ListNodeClass();
		ListNodeClass LNC2 = new ListNodeClass();

		boolean isCircle1 = isCircle(head1,LNC1);
		boolean isCircle2 = isCircle(head2,LNC2);

		System.out.println("isCircle1: "+isCircle1);
		System.out.println("isCircle2: "+isCircle2);


		if(isCircle1!=isCircle2)
			return false;
		else if(!isCircle1 && !isCircle2)
			// 无环 ,比较尾节点
			return LNC1.lastNode == LNC2.lastNode;
		else{
			//判断同一个,两个带环链表是同一个链表
			if(LNC1.circleNode == LNC2.circleNode)
				return true;
			// 从其中一个相遇点出发
			ListNode tempNode = LNC1.circleNode.getNext();
			// 跳出循环条件是 走了一圈
			while(tempNode != LNC1.circleNode){
				//碰到了 circleNode2就是说在环内
				System.out.println("碰到了 circleNode2就是说在环内");
				if(tempNode == LNC2.circleNode)
				{
					System.out.println("tempNode == LNC2.circleNode");
					return true;
				}
				tempNode = tempNode.getNext();
			}
			return false;
		}
	}
}


寻找两链表相交的第一个点,这部分已经时间看了,mark一个

找到环的入口,这博文写得不错的。

本次学习毕。

标题基于SpringBoot+Vue的学生交流互助平台研究AI更换标题第1章引言介绍学生交流互助平台的研究背景、意义、现状、方法与创新点。1.1研究背景与意义分析学生交流互助平台在当前教育境下的需求及其重要性。1.2国内外研究现状综述国内外在学生交流互助平台方面的研究进展与实践应用。1.3研究方法与创新点概述本研究采用的方法论、技术路线及预期的创新成果。第2章相关理论阐述SpringBoot与Vue框架的理论基础及在学生交流互助平台中的应用。2.1SpringBoot框架概述介绍SpringBoot框架的核心思想、特点及优势。2.2Vue框架概述阐述Vue框架的基本原理、组件化开发思想及与前端的交互机制。2.3SpringBoot与Vue的整合应用探讨SpringBoot与Vue在学生交流互助平台中的整合方式及优势。第3章平台需求分析深入分析学生交流互助平台的功能需求、非功能需求及用户体验要求。3.1功能需求分析详细阐述平台的各项功能需求,如用户管理、信息交流、互助学习等。3.2非功能需求分析对平台的性能、安全性、可扩展性等非功能需求进行分析。3.3用户体验要求从用户角度出发,提出平台在易用性、美观性等方面的要求。第4章平台设计与实现具体描述学生交流互助平台的架构设计、功能实现及前后端交互细节。4.1平台架构设计给出平台的整体架构设计,包括前后端分离、微服务架构等思想的应用。4.2功能模块实现详细阐述各个功能模块的实现过程,如用户登录注册、信息发布与查看、在线交流等。4.3前后端交互细节介绍前后端数据交互的方式、接口设计及数据传输过程中的安全问题。第5章平台测试与优化对平台进行全面的测试,发现并解决潜在问题,同时进行优化以提高性能。5.1测试境与方案介绍测试境的搭建及所采用的测试方案,包括单元测试、集成测试等。5.2测试结果分析对测试结果进行详细分析,找出问题的根源并
内容概要:本文详细介绍了一个基于灰狼优化算法(GWO)优化的卷积双向长短期记忆神经网络(CNN-BiLSTM)融合注意力机制的多变量多步时间序列预测项目。该项目旨在解决传统时序预测方法难以捕捉非线性、复杂时序依赖关系的问题,通过融合CNN的空间特征提取、BiLSTM的时序建模能力及注意力机制的动态权重调节能力,实现对多变量多步时间序列的精准预测。项目不仅涵盖了数据预处理、模型构建与训练、性能评估,还包括了GUI界面的设计与实现。此外,文章还讨论了模型的部署、应用领域及其未来改进方向。 适合人群:具备一定编程基础,特别是对深度学习、时间序列预测及优化算法有一定了解的研发人员和数据科学家。 使用场景及目标:①用于智能电网负荷预测、金融市场多资产价格预测、境气象多参数预报、智能制造设备状态监测与预测维护、交通流量预测与智慧交通管理、医疗健康多指标预测等领域;②提升多变量多步时间序列预测精度,优化资源调度和风险管控;③实现自动化超参数优化,降低人工调参成本,提高模型训练效率;④增强模型对复杂时序数据特征的学习能力,促进智能决策支持应用。 阅读建议:此资源不仅提供了详细的代码实现和模型架构解析,还深入探讨了模型优化和实际应用中的挑战与解决方案。因此,在学习过程中,建议结合理论与实践,逐步理解各个模块的功能和实现细节,并尝试在自己的项目中应用这些技术和方法。同时,注意数据预处理的重要性,合理设置模型参数与网络结构,控制多步预测误差传播,防范过拟合,规划计算资源与训练时间,关注模型的可解释性和透明度,以及持续更新与迭代模型,以适应数据分布的变化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值