链表顺序表常见面试题(4)——Java语言实现

判断两个链表是否相交,若相交,求交点。(假设链表不带环)
step1:在不带环的情况下对链表是否相交进行判断,即遍历两个链表,
链表的最后一个节点的值相等则表明链表相交。
step2:求交点,我们可以先对两链表的长度进行比较,使得长的链表先走长度差步,
然后两个链表一起走,当两个链表遇到第一个所对应节点的值相等时,则就是交点。
/**
 *@Description: 判断两个链表是否相交,若相交,求交点(假设链表不带环)
 *@Author: dyy
 */
public class ListMeet {
    public static void main(String[] args) {
        ListNode head1 = new ListNode("lemon");
        head1.nextNode = new ListNode("lll");
        head1.nextNode.nextNode = new ListNode(1);
        head1.nextNode.nextNode.nextNode = new ListNode('a');
        head1.nextNode.nextNode.nextNode.nextNode = new ListNode(5);
        ListNode head2 = new ListNode("demon");
        head2.nextNode = new ListNode("gj");
        head2.nextNode.nextNode = new ListNode('a');
        head2.nextNode.nextNode.nextNode = new ListNode(5);
    }
    public  ListNode twoLikeMeet(ListNode head1,ListNode head2) {
        //两个链表有一个为空时
        if (head1 == null || head2 == null) {
            return null;
        }
        int length1 = getLength(head1);
        int length2 = getLength(head2);
        //记录两个链表的长度差
        int lengthDif = 0;
        ListNode longNode;
        ListNode shortNode;
        if (length1 > length2) {
            longNode = head1;
            shortNode = head2;
            lengthDif = length1 - length2;
        } else {
            longNode = head2;
            shortNode = head1;
            lengthDif = length2 - length1;
        }
        //将较长的链表先向前走长度差步
        for (int i = 0; i < lengthDif; i++) {
            longNode = longNode.nextNode;
        }
        //将两个节点同时向后移动,第一个相等的点即为交点
        while (longNode != null && shortNode != null) {
            if (longNode.data == shortNode.data) {
                return longNode;
            }
            longNode = longNode.nextNode;
            shortNode = shortNode.nextNode;
        }
        return null;
    }
    //求链表的长度
    public static int getLength(ListNode head) {
        if (head == null) {
            return 0;
        }
        int count = 0;
        ListNode cur = head;
        while (cur != null) {
            count++;
            cur = cur.nextNode;
        }
        return count;
    }

    public  boolean hasIntersection(ListNode head1, ListNode head2){
        ListNode fast = head1;
        ListNode slow = head2;
        if(fast==null||slow==null){
            return false;
        }
        while (fast!=null){
            fast = fast.nextNode;
        }
        while (slow!=null){
            slow = slow.nextNode;
        }
        if(fast==slow){
            return true;
        }
        return  false;
    }
}

 /**
    *@Description: 判断两个链表是否相交,若相交,求交点(假设链表不带换)测试函数
    *@Author: dyy
    */
    @Test
    public void test_ListMeet(){
        ListNode head1 = new ListNode("lemon");
        head1.nextNode = new ListNode("lll");
        head1.nextNode.nextNode = new ListNode(1);
        head1.nextNode.nextNode.nextNode = new ListNode('a');
        head1.nextNode.nextNode.nextNode.nextNode = new ListNode(5);
        ListNode head2 = new ListNode("demon");
        head2.nextNode = new ListNode("gj");
        head2.nextNode.nextNode = new ListNode('a');
        head2.nextNode.nextNode.nextNode = new ListNode(5);
        ListMeet listMeet = new ListMeet();
        if(listMeet.hasIntersection(head1,head2)==true){
            System.out.println(listMeet.twoLikeMeet(head1,head2).data);
        }else{
            System.out.println("两个链表不相交");
        }
    }
复杂链表的复制。一个链表的每个节点,有一个指向next指针指向下一个节点,还有一个random指针指向这个链表中的一个随机节点或者NULL,现在要求实现复制这个链表,返回复制后的新链表。
step1:我们对链表的各个节点进行复制,并且在每一个节点后面添加新的节点
step2: 改变新增节点的random指针的指向
step3:对链表进行拆分
public class ComplexListClone {
    //复杂链表的复制
    public static RandomListNode RandomListNodeClone(RandomListNode head) {
        if (head == null) {
            return null;
        }
        copyNodes(head);
        setCloneNode(head);
        return spiltNodes(head);
    }

    //复制链表上的节点并且在每一个节点后面添加新的节点
    public static void copyNodes(RandomListNode head) {
        RandomListNode temp = head;
        while (temp != null) {
            RandomListNode cloneNode = new RandomListNode(0);
            cloneNode.next = temp.next;
            cloneNode.label = temp.label;
            cloneNode.random = null;
            temp.next = cloneNode;
            temp = cloneNode.next;
        }
    }

    //设置复制出来的节点的指向
    public static void setCloneNode(RandomListNode head) {
        RandomListNode pNode = head;
        while (pNode != null) {
            RandomListNode pClone = pNode.next;
            if (pNode.random != null) {
                pClone.random = pNode.random.next;
            }
            pNode = pClone.next;
        }
    }

    //将链表分为两个链表
    public static RandomListNode spiltNodes(RandomListNode head) {
        RandomListNode pNode = head;
        RandomListNode cloneHead = null;
        RandomListNode cloneNode = null;
        if (pNode != null) {
            cloneHead = pNode.next;
            cloneNode = pNode.next;
            pNode.next = cloneNode.next;
            pNode = pNode.next;
        }
        while (pNode != null) {
            cloneNode.next = pNode.next;
            cloneNode = cloneNode.next;
            pNode.next = cloneNode.next;
            pNode = pNode.next;
        }
        return cloneHead;
    }
}
/**
    *@Description: 复杂链表的复制测试
    *@Author: dyy
    */
    @Test
    public void test_ComplexListClone(){
        RandomListNode randomListNode = new RandomListNode(1);
        randomListNode.next = new RandomListNode(3);
        RandomListNode randomListNode2 = randomListNode.next;
        randomListNode.next = new RandomListNode(65);
        RandomListNode randomListNode3 = randomListNode2.next;
        randomListNode.next = new RandomListNode(2);
        randomListNode.random = randomListNode3;
        randomListNode2.random = randomListNode;
        System.out.println(ComplexListClone.RandomListNodeClone(randomListNode).label);
    }
求两个已排序单链表中相同的数据。
求两个已经排序好单链表中相同的数据,我们可以使用用一个链表的一个值
另外一个链表的所有值进行比较,相同则输出,但是这样的复杂度就特别高;
但我们可以使用和并两个排序好的单链表具有相同的思路,设置两个节点,
当其中一个值大时,就向后移动,相等则输出任意节点,同时移动这两个节点。
/**
*@Description: 求两个已排序链表中的相同元素
*@Author: dyy
*/
public class SortListHasEqualElements{
    public static void FindEqualElements(ListNode head1,ListNode head2){
        ListNode cur1 = head1;
        ListNode cur2 = head2;
        if(head1==null||head2==null){
            System.out.println("两个链表中有其一为空");
        }
        //降序和升序的判断(假设1为升序,0为降序)
        int flag = 1;
        //降序
        if(cur1.data > cur1.nextNode.data){
            flag = 0;
        }
        while (cur1!=null&&cur2!=null){
            if(cur1.data>cur2.data){
                if(0 == flag){
                    cur1 = cur1.nextNode;
                }else{
                    cur2 = cur2.nextNode;
                }
            }else if(cur1.data==cur2.data){
                System.out.print(cur1.data+"->");
                cur1=cur1.nextNode;
                cur2=cur2.nextNode;
            }else if(cur1.data<cur2.data){
                if(0==flag){
                    cur2 = cur2.nextNode;
                }else{
                    cur1 = cur1.nextNode;
                }
            }
        }
    }
 /**
     *@Description: 求两个已排序链表中的相同元素测试函数
     *@Author: dyy
     */
    @Test
    public void test_FindEqualElements(){
        ListNode head1 = new ListNode(1);
        head1.nextNode = new ListNode(3);
        head1.nextNode.nextNode = new ListNode(5);
        head1.nextNode.nextNode.nextNode = new ListNode(7);
        ListNode head2 = new ListNode(0);
        head2.nextNode = new ListNode(2);
        head2.nextNode.nextNode = new ListNode(3);
        head2.nextNode.nextNode.nextNode = new ListNode(5);
        SortListHasEqualElements.FindEqualElements(head1,head2);
    }
比较顺序表和链表的优缺点,他们分别在什么场景下使用它?
  • 顺序表支持随机访问,而单链表不支持随机访问.
  • 顺序表插入/删除数据效率很低,时间复杂度为O(N)(除尾插尾删),单链表插入和删除效率更高,时间复杂度为O(1).
  • 顺序表的CPU高速缓存效率更高,单链表CPU高速缓存效率低.
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值