左程云 Java 笔记--链表


1哈希表

在这里插入图片描述

2有序表

在这里插入图片描述
在这里插入图片描述

3链表

在这里插入图片描述

3.1打印两个有序链表的公共部分

[题目] 给定两个有序链表的头指针head1和head2,打印两个链表的公共部分。
[要求] 如果两个链表的长度之和为N,时间复杂度要求为0(N),额外空间复
杂度要求为0(1)

3.2判断一个链表是否为回文结构

[题目]给定一个单链表的头节点head,请判断该链表是否为回文结构。
[例子] 1->2->1,返回true; 1->2- ->2- >1,返回true; 15- ->6- ->15,返回true; 1->2- >3,返回false。
[例子]如果链表长度为N,时间复杂度达到0 (N),额外空间复杂度达到0(1)。
笔试做法:放入栈中,然后依次弹出对比,有不一样的就是回文
面试做法:(省空间)
①只把右边的放入栈中,栈只要弹空了且都想等 就是回文 ==>快慢指针

在这里插入图片描述

// n space
    public static boolean isPailndrome1(Node head){
        Stack<Node> stack = new Stack<>();
        Node cur = head;
        while (cur != null){
            stack.push(cur);
            cur = cur.next;
        }
        while(head != null){
            if (head.value != stack.pop().value){
                return false;
            }
            head = head.next;
        }
        return true;
    }
    // n/2 space
    public static boolean isPailndrome2(Node head){
        if (head == null || head.next == null){
            return true;
        }
        Node right = head.next;
        Node cur = head;
        while (cur.next != null && cur.next.next != null){
            right = right.next;
            cur = cur.next.next;
        }
        Stack<Node> stack = new Stack<>();
        while (right != null){
            stack.push(right);
            right = right.next;
        }
        while (! stack.isEmpty()){
            if (head.value != stack.pop().value){
                return false;
            }
            head = head.next;
        }
        return true;
    }

    // o(1) space
    public static boolean isPailndrome3(Node head){
        if (head == null || head.next == null){
            return true;
        }
        Node node1 = head;
        Node node2 = head;
        while (node1.next != null && node2.next.next != null){
            node1 = node1.next;
            node2 = node2.next.next;
        }
        //反转后半部分
        node2 = node1.next;
        node1.next = null;
        Node node3 = null;
        while (node2 != null){
            node3 = node2.next;
            node2.next = node1;
            node1 = node2;
            node2 = node3;
        }
        node3 = node1;
        node2 = head;
        boolean res = true;
        while (node1 != null && node2 != null){
            if (node1.value != node2.value){
                return false;
            }
            node1 = node1.next;
            node2 = node2.next;
        }
        //恢复
        node1 = node3.next;
        node3.next = null;
        while (node1 != null){
            node2 = node1.next;
            node1.next = node3;
            node3 = node1;
            node1 = node2;
        }
        return res;
    }

    public static class Node{
        public int value;
        public Node next;

        public Node(int value) {
            this.value = value;
        }
    }

3.3将单向链表按某值划分成左边小、中间相等、右边大的形式

[题目]给定一个单链表的头节点head,节点的值类型是整型,再给定一个整数pivot。实现- -个调整链表的函数,将链表调整为左部分都是值小于pivot的节点,中间部分都是值等于pivot的节点,右部分都是值大于pivot的节点。
[进阶]在实现原问题功能的基础上增加如下的要求
[要求]调整后所有小于pivot的节点之间的相对顺序和调整前一样
[要求]调整后所有等于pivot的节点之间的相对顺序和调整前一样
[要求]调整后所有大于p ivot的节点之间的相对顺序和调整前一样
[要求]时间复杂度请达到0(N),额外空间复杂度请达到0(1)。
在这里插入图片描述

    public static Node listPartition2(Node head, int pivot){
        Node sH = null;
        Node sT = null;
        Node eH = null;
        Node eT = null;
        Node mH = null;
        Node mT = null;
        Node next = null;

        while (head != null){
            next = head.next;
            head.next = null;
            if (head.value < pivot){
                if (sH == null){
                    sH = head;
                    sT = head;
                }else {
                    sT.next = head;
                    sT = head;
                }
            }else if (head.value == pivot){
                if (eH == null){
                    eH = head;
                    eT = head;
                }else {
                    eT.next = head;
                    eT = head;
                }
            }else {
                if (mH == null){
                    mH = head;
                    mT = head;
                }else {
                    mT.next = head;
                    mT = head;
                }
            }
            if (sT != null){
                sT.next = eH;
                eT = eT == null? sT : eT;
            }
            if (eT != null){
                eT.next = mH;
            }
        }
        return sH != null ? sH : (eH != null ? eH : mH);
    }

3.4复制含有随机指针节点的链表

[题目]一种特殊的单链表节点类描述如下

class Node{
	int value;
	Node next ;
	Node rand ;
	Node(int val) {
		value = val ;
	}
}

rand指针是单链表节点结构中新增的指针,rand可 能指向链表中的任意一个节点,也可能指向null。给定一个由Node节点类型组成的无环单链表的头节点head,请实现一个函数完成这个链表的复制,并返回复制的新链表的头节点。
[要求]时间复杂度0 (N),额外空间复杂度0(1)

3.4.1使用哈希表

在这里插入图片描述

   //metho1 HashMap
    public static Node copyListWithRand1(Node head){
        HashMap<Node,Node> map = new HashMap<>();
        Node cur = head;
        while (cur != null){
            map.put(cur,new Node(cur.value));
            cur = cur.next;
        }
        cur = head;
        while (cur != null){
            map.get(cur).next = map.get(cur.next);
            map.get(cur).rand = map.get(cur.rand);
            cur = cur.next;
        }
        return map.get(head);
    }

3.4.2方法二

在这里插入图片描述

//metho2
    public static Node copyListWithRand2(Node head){
        if (head == null){
            return null;
        }
        Node cur = head;
        Node next = null;
        while (cur != null){
            next = cur.next;
            cur.next = new Node(cur.value);
            cur.next.next = next;
            cur = next;
        }
        cur = head;
        Node curCopy = null;
        while (cur != null){
            next = cur.next.next;
            curCopy = cur.next;
            curCopy.rand = cur.rand != null ? cur.rand.next :null;
            cur = next;
        }
        Node res = head.next;
        cur = head;
        while (cur != null){
            next = cur.next.next;
            curCopy = cur.next;
            cur.next = next;
            curCopy.next = next != null ? next.next : null;
            cur = next;
        }
        return resl;
    }

3.5两个单链表相交的一系列问题

[题目]给定两个可能有环也可能无环的单链表,头节点head1和head2。请实现一个函数,如果两个链表相交,请返回相交的第- -个节点。如果不相交,返回nulI
[要求]如果两个链表长度之和为N,时间复杂度请达到0 (N),额外空间复杂度请达到0(1)。

3.5.1先判断是否有环: 用HashSet/快慢指针

    public static Node getLoopNode(Node head){
        if (head == null || head.next == null || head.next.next == head){
            return null;
        }
        Node n1 = head.next;
        Node n2 = head.next.next;
        while (n1 != n2){
            if (n2.next == null || n2.next.next == null){
                return null;
            }
            n1 = head.next;
            n2 = head.next.next;
        }
        n2 = head;
        while (n1 != n2){
            n1 = n1.next;
            n2 = n2.next;
        }
        return n1;
    }

3.5.2无环情况

在这里插入图片描述
先判断最后一个节点地址是否一样
在这里插入图片描述

    //无环
    public static Node noLoop(Node head1, Node head2){
        if (head1 == null || head2 == null){
            return null;
        }
        Node cur1 = head1;
        Node cur2 = head2;
        int n = 0;
        while (cur1.next != null){
            n++;
            cur1 = cur1.next;
        }
        while (cur2.next != null){
            n--;
            cur2 = cur2.next;
        }
        if (cur1 != cur2){
            return  null;
        }
        cur1 = n > 0 ? head1 : head2;//谁长谁是cur1
        cur2 = cur1 == head1? head2 : head1; //谁短谁是cur2
        n = Math.abs(n);
        while (n != 0){
            cur1 = cur1.next;
            n--;
        }
        while (cur1 != cur2){
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        return cur1;
    }

3.5.3一个为有环一个为无环

不可能相交!!!!

3.5.4都为环形

三种情况
在这里插入图片描述

   //有环
    public static Node bothLoop(Node head1, Node head2,Node loop1, Node loop2){
        Node cur1 = null;
        Node cur2 = null;
        if (loop1 == loop2){
            cur1 = head1;
            cur2 = head2;
            int n = 0;
            while (cur1 != loop1){
                n++;
                cur1 = cur1.next;
            }
            while (cur2 != loop2){
                n--;
                cur2 = cur2.next;
            }
            cur1 = n > 0 ? head1 : head2;//谁长谁是cur1
            cur2 = cur1 == head1? head2 : head1; //谁短谁是cur2
            n = Math.abs(n);
            while (n != 0){
                cur1 = cur1.next;
                n--;
            }
            while (cur1 != cur2){
                cur1 = cur1.next;
                cur2 = cur2.next;
            }
            return cur1;
        }else {
            cur1 = loop1.next;
            while (cur1 != loop1){
                if (cur1 == loop2){
                    return loop1;
                }
                cur1 = cur1.next;
            }
            return null;
        }
    }

主函数

//方法
    public static Node getNode(Node head1, Node head2){
        if (head1 == null || head2 == null){
            return null;
        }
        Node loop1 = getLoopNode(head1);
        Node loop2 = getLoopNode(head2);
        if (loop1 == null && loop2 == null){
            return noLoop(head1,head2);
        }
        if (loop1 != null && loop2 != null){
            return bothLoop(head1,head2,loop1,loop2);
        }
        return null;
    }

总结

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值