链表之实际问题3


1. 输入两个链表,找出它们的第一个公共结点。


1>. 判断两个链表是否有公共节点
2.>先分别求出两个链表的长度lenA和lenB,定义两个引用longer=headA和shorter=headB
3>.定义一个引用diff=两个链表的长度差,
4>.让较长的longer先走diff步,然后两个链表一起开始走
5>.判断longer是否等于shorter,不等于则没有公共节点,否则有公共节点。
主要代码:

class ListNode {
    public int val;
    public ListNode next;
//构造方法
    public ListNode(int val, ListNode next) {
        this.val = val;
        this.next = next;
    }
    public ListNode(int val) {
        this(val, null);
    }
}
public class Solution {
	//获取链表长度方法
    private int getLength(ListNode head) {
        int len = 0;
        for (ListNode c = head; c != null; c = c.next) {
            len++;
        }
        
        return len;
    }
	
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int lenA = getLength(headA);
        int lenB = getLength(headB);
        //获取链表长度,并求取长度差
        ListNode longer = headA;
        ListNode shorter = headB;
        int diff = lenA - lenB;
        if (lenA < lenB) {
            longer = headB;
            shorter = headA;
            diff = lenB - lenA;
        }
        //让longer先走长度差步
        for (int i = 0; i < diff; i++) {
            longer = longer.next;
        }
        //判断是否右公共节点
        while (longer != shorter) {
            longer = longer.next;
            shorter = shorter.next;
        }
        
        return longer;
    }
}

10. 给定一个链表,判断链表中是否有环,并返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL


1>.快慢指针,快的走两步,慢的走一步,(快的不可以比慢的多走超过一步)fast 遇到 null,表示不带环,返回 null, fast == slow,表示遇到相遇点了
2.>找环的入口: 1.把环转化转为相交问题,2.一个引用从起点出发,一个引用从相遇点出发,一定会在环的入口点相遇
3.>证明: 1.满引用走L+C 2.快引用走的距离L+C+(n+1)R 3.快引用走的距离2(L+C)
2和3相等,可证
4.>相遇点的距离到入口点的距离和起点到入口点的距离相等。

主要代码:

class ListNode {
    public int val;
    public ListNode next;
//构造方法
    public ListNode(int val, ListNode next) {
        this.val = val;
        this.next = next;
    }
    public ListNode(int val) {
        this(val, null);
    }
}
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        // fast 遇到 null,表示不带环,返回 null
        // fast == slow,表示遇到相遇点了
        do {
            if (fast == null) {
                return null;
            }
            fast = fast.next;
            if (fast == null) {
                return null;
            }
            fast = fast.next;
            slow = slow.next;
        } while (fast != slow);
        // 求相遇点
        // 如果快的遇到 null,表示没有环,直接返回 null
        // 相遇点出发 + 起点出发,最终相遇
        ListNode p = head;              //记录起点
        ListNode q = slow;           //记录相遇点
        while (p != q) {
            p = p.next;
            q = q.next;
        }
        
        return q;
    }


3. 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。要求返回这个链表的深度拷贝


1.先复制所有的节点
1.1 用p1遍历原链表的所有节点,把p2插入到p1的后面
1.2 定义一个引用p1=head,如果head不为null,新建一个引用p2,使其完全等于p1,然后让p2尾插到p1后面,即p2.next = p1.next;p1.next = p2;p1 = p2.next;
1.3 p1=p1.next,继续执行,直到将原链表的所有节点复制完并且均插入到原链表的后面
2.处理random的指向
2.1 原来的链表的random的指向为1==>3,2==>1,3==>3,4==>null,复制之后的新链表也要是1==>3,2==>1,3==>3,4==>null
2.2 如果p1!=null,让p1=head(改变之后的链表的head)p2=p1.next;注意到p2.random所指的节点一直在p1.random的后一个节点,所以p2.random = p1.random.next;
2.3 p1 = p2.next;继续循环,知道所有rsndom的指向处理完毕技术循环
3.将链表分离
3.1 改变链表的指向即可。
在这里插入图片描述
完整代码:

class CNode {
   public int val;
   public CNode next = null;
   public CNode random = null;

    public CNode(int val) {
        this.val = val;
    }
}
public class Solution5{
	//复制所有节点
	//定义一个引用p1=head,如果head不为null,新建一个引用p2,使其完全等于p1,然后让p2尾插到p1后面,即p2.next = p1.next;p1.next = p2;p1 = p2.next;
	//p1=p1.next,继续执行,直到将原链表的所有节点复制完并且均插入到原链表的后面
	//
    public CNode complexCopy(CNode head) {
        if (head == null) {
            return null;
        }
		//复制并插入到原链表的后面
        CNode p1 = head;
        while (p1 != null) {
            CNode p2 = new CNode(p1.val);
            p2.next = p1.next;
            p1.next = p2;

            p1 = p2.next;
        }
//处理random的指向
//原来的链表的random的指向为1==>3,2==>1,3==>3,4==>null,复制之后的新链表也要是1==>3,2==>1,3==>3,4==>null
//如果p1!=null,让p1=head(改变之后的链表的head)p2=p1.next;注意到p2.random所指的节点一直在p1.random的后一个节点,所以p2.random = p1.random.next;
//p1 = p2.next;继续循环,知道所有rsndom的指向处理完毕技术循环
        p1 = head;
        while (p1 != null) {
            CNode p2 = p1.next;
            if (p1.random != null) {
                p2.random = p1.random.next;
            }

            p1 = p2.next;
        }
//分离链表
//改变链表的指向即可
        p1 = head;                //回复p1的指向
        CNode newHead = head.next;     //保存新链表的head

        while (p1 != null) {
            CNode p2 = p1.next;

            p1.next = p2.next;
            if (p2.next != null) {
                p2.next = p2.next.next;
            }

            p1 = p1.next;
        }

        return newHead;
    }

	//深度拷贝的创建链表
    private static void testComplexCopy(Solution5 solution) {
        CNode n1 = new CNode(1);
        CNode n2 = new CNode(2);
        CNode n3 = new CNode(3);
        CNode n4 = new CNode(4);

        n1.random = n3; n2.random = n1; n3.random = n3;
        n1.next = n2; n2.next = n3; n3.next = n4;

        CNode result = solution.complexCopy(n1);
       while(result!=null){
		   System.out.println(result.val);
		   result=result.next;
	   }
        System.out.println("成功");
    }
public static void main(String[] args) {
        Solution5 solution = new Solution5();
        testComplexCopy(solution);
    }
	
}

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值