单链表相关的面试题

面试题1:删除值为key的所有节点 要求只遍历一遍

public Node removeAllKey(int key) {     
        if (this.head == null) {
            return null;
        }
        Node prev = this.head;
        Node cur = this.head.next;
        while (cur != null) {
            if (cur.data == key) {
                prev.next = cur.next;
                cur = cur.next;
            } else {
                prev = cur;
                cur = cur.next;
            }
        }
        if (this.head.data == key) {
            this.head = this.head.next;
        }
        return head;         // 返回的是一个头节点  head
    }

面试题2: 反转单链表

public Node reverseList() {            
        Node prev = null;
        Node cur = this.head;
        Node curNext = null;
        Node newHead = null;
        while (cur != null) {
            curNext = cur.next;
            if (curNext == null) {
                newHead = cur;
            }
            cur.next = prev;
            prev = cur;
            cur = curNext;
        }
        return newHead;
    }

面试题3: 查找链表的中间节点 如果是偶数个 输出第二个

public Node middleNode() {       
        Node fast = this.head;
        Node slow = this.head;
        if (this.head == null) {
            return null;
        }
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

面试题4:找出链表的倒数第K个节点 遍历一次单链表

 public Node FindKthTOTail(int k) {
        if (this.head == null) {
            return null;
        }
        if (k < 1) {
            System.out.println("K是不合法的");
            return null;
        }
        Node fast = this.head;
        Node slow = this.head;
        while (k - 1 > 0) {
            if (fast.next != null) {
                fast = fast.next;
                k--;
            } else {
                System.out.println("没有这个节点");
                return null;
            }
        }
        while (fast.next != null) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }

以定值x为基准将链表分割成俩部分,所有小于x的节点排在大于或等于x的节点之前,保持顺序不变

思路:1、俩个线段开始还有结束 bs be as ae = null
2、定义一个cur遍历原来的单链表
3、如果 cur.data < x 放到第一个线段 , 如果相反,放到第二个线段 采用尾插法
4、当cur为空的时候 原来的单链表就遍历完了
注意: 1、第一个线段没有数据 返回as
2、be 和 as 拼接 be.next = as;
3、判断第一次插入 as = cur ; ae = cur;

public Node partition(int x){
        Node bs = null;
        Node be = null;
        Node as = null;
        Node ae = null;
        Node cur = this.head;
        while (cur != null){
            if (cur.data < x){
                //分为第一次插入和不是第一次插入
                if (bs == null){
                    bs = cur;
                    be = cur;
                }else {
                    be.next = cur;
                    be =be.next;
                }
            }else {
                if (as == null){
                    as = cur;
                    ae = cur;
                }else {
                    ae.next =cur;
                    ae = ae.next;
                }
            }
            cur = cur.next;
        }
        //判断 bs 是否为空    如果 bs == null  返回as
        //如果  bs不为空   需要进行拼接
        //如果ae不为空, ae.next = null  be.next = as;
        if (bs == null){
            return as;
        }
        be.next = as;
        if (ae != null){
            ae.next=null;
        }
        return bs;
    } 

面试题7:删除排序的链表中重复的节点

public  Node deleteDuplication(){
        Node cur = this.head;
        Node newHead = new Node(-1);
        Node tmp = newHead ;
        while (cur != null){
            if (cur.next!=null &&cur.data==cur.next.data){
                while (cur.next != null &&cur.data == cur.next.data){
                    cur = cur.next;
                }
                cur = cur.next;  // 多走一步
            }else {
                tmp.next =cur;
                tmp = tmp.next;
                cur = cur.next;
            }
        }
        tmp.next = null ;
        return newHead.next;
    }

面试题8:链表的回文结构

思路://1.找到中间节点
//2,开始反转单链表
//3.一个从头走 一个从尾走

public boolean chkPalindrome(){
        Node fast = this.head;
        Node slow =this.head;
        if (this.head==null){
            return false;
        }
//        if (this.head==null){        //在牛客上   没有规定为空会怎样
//            return true ;
//        }
        if (fast!= null && fast.next!=null){   // 找到中间节点
            fast = fast.next.next;
            slow = slow.next;
        }
        Node cur = slow.next;
        while (cur != null){          //  开始反转后半部分单链表  此时slow在中间位置
            Node curNext =cur.next;
            cur.next =slow;
            slow =cur;
            cur = curNext;
        }  //此时slow是最后一个节点  开始第三步
        while (this.head != slow){         //一个从头走   一个从尾走
            if (this.head.data != slow.data){
               return false;
            }
            if (this.head.next==slow){   //判断偶数的情况
                return true;
            }
                head = head.next;
                slow = slow.next;
        }
        return true;
    }

面试题10 给定一个链表,判断链表中是否有环

思路:定义 fast slow 速度不一样
* 如果有环 会相遇 如果没环 不会相遇
* 快的一次俩步 慢的一次一步
* 否则 要么很慢相遇 要么永远相遇不了

public boolean hasCycle(){
        Node fast = this.head;
        Node slow = this.head;
        while (fast != null && fast.next != null){
            fast=fast.next.next;
            slow=slow.next;
            if (fast==slow){
                return true;
            }
        }
        return false;
    }

面试题11:给定一个链表,返回链表开始入环的第一个节点,如果链表无环,返回 null

思路:设 头节点距离入口节点 为 x
在环内 距 入口节点 y处相遇 环长为 c
fast多走一圈相遇时 慢引用路程 X+(C-Y)
快引用 X+C+(C-Y)
快引用路程是慢引用的二倍
2*[X+(C-Y)] = X+C+(C-Y)
化简得 X= Y
此时圈小,但是为啥一定在慢的走第一圈就遇到呢?不可以是慢的走第二圈吗?
fast多走 n 圈相遇时 慢引用路程 X+nC+(C-Y)
快引用 X+nC+(C-Y)
快引用路程是慢引用的二倍
2*[X+(C-Y)] = X+nC+(C-Y)
化简得 X-Y= nC-C
X = (n-1)C+Y
// 相遇后 fast 走n圈 加 y 等于slow从头节点出发
相遇时正好在入环点
化简后 可知 相遇节点 顺时针 距离 入口节点 为 x
于是 头节点 和 相遇节点 一人一步 便是 入口节点

public  Node detectCycle(){
        Node fast = this.head;
        Node slow = this.head;
        while (fast!=null && fast.next!=null) {
            fast = fast.next.next;
            slow = slow.next;
            if (slow == fast) {
                break;
            }
        }
            if (fast==null || fast.next==null){
                return null;
            }
            slow =this.head;
            while (fast!= slow){
                slow= slow.next;
                fast = fast.next;
            }
            return slow;
        }

面试题9:输入俩个链表,找出他们的第一个公共节点

思路: 求俩个单链表的长度 pl指向长的链表 ps指向短的链表
2. 计算长度的差值 让长的先走差值步

 public static  Node getIntersectionNode(Node headA ,Node headB){
        int lenA = 0;
        int lenB = 0;
        Node pl = headA ;
        Node ps = headB ;

        while ( pl !=null ){
            lenA++;
            pl = pl.next;
        }
        while (ps !=null){
            lenB++;
            ps = ps.next;
        }
        pl = headA;
        ps = headB;
        int len = lenA - lenB;
        if (len < 0) {
            pl = headB;
            ps = headA;
            len = lenB - lenA ;
        }

        // 1.  pl指向最长的单链表
        for (int i = 0; i < len ; i++) {
            pl = pl.next;
        }
        // 2.  ps 和 pl  在同一个起跑线上
        while (ps != pl && pl!=null  && ps != null){
            ps = ps.next;
            pl = pl.next;
        }
        if (pl == ps && pl !=null  && ps!=null){
            return pl;
        }
        return null;
    }

面试题5: 合并俩个有序链表

 public static Node  mergeTwoLists(Node headA,Node headB){
        Node newHead = new Node(-1);
        Node tmp = newHead;
        while (headA!=null && headB!=null){
            if (headA.data < headB.data){
                tmp.next = headA;
                tmp = tmp.next;
                headA = headA.next;
            }else {
                tmp.next = headB;
                tmp = tmp.next;
                headB = headB.next;
            }
        }
        if (headA==null){
            tmp.next = headB;
        }
        if (headB==null){
        tmp.next = headA;
        }
        return newHead.next;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值