白银挑战-链表的高频算法面试题

单链表的定义

public class NodeList {
    int val;
    NodeList next;

    //初始化一个单向链表
    public NodeList(int val){
        this.val=val;
        next=null;
    }
}

1.两个链表的第一个公共字节点

方法一思路:链表A存入Hashset集合,并遍历Hashset集合查看B中是否有节点与之匹配,若有则是链表AB的第一个公共字节点,若无则AB链表无公共字节点

  public NodeList findCommomNode(NodeList headA,NodeList headB){
        //定义一个hashset:无序且不重复;用来存放A链表
        HashSet<NodeList> set = new HashSet<>();
        while (headA!=null){
            set.add(headA);
            headA=headA.next;
        }

        while (headB!=null){
            if (set.contains(headB))
                return headB;
                headB = headB.next;
        }
        return null;
    }

方法二思路:栈(先进后出)存放链表,并遍历查找直到链表的栈顶元素不同,则共同节点则是此时栈顶元素的前一个

 //栈的做法
    public NodeList findCommomNodeByTrack(NodeList headA,NodeList headB){
        //创建两个栈对象,用于存放链表A和链表B
        Stack<NodeList> stackA = new Stack<>();
        Stack<NodeList> stackB = new Stack<>();
        while (headA!=null){
            stackA.push(headA);
            headA=headA.next;
        }
        while (headB!=null){
            stackA.push(headB);
            headB=headB.next;
        }
        NodeList preNode = null;
       while (stackA.size()>0 && stackB.size() > 0){
           //查看栈顶元素是否相同
           if (stackA.peek()==stackB.peek()){
               preNode=stackA.pop();
               stackB.pop();
           }else {
               break;
           }
       }
         return preNode;
    }

2.判断链表是否位回文链表

1-2-2-1 为回文链表,1-2-3-1不是

思路:将要判断的链表head放入栈中stackNodeList,一边stackNodeList出栈一边遍历head链表,并比较,若有一个不相等,则不是回文链表

 public boolean isReturnNodeList(NodeList head){
        NodeList temp = head;
        Stack<Integer> stackNodeList = new Stack<>();
        //把链表节点的值放至栈中
        while (temp!=null){
            stackNodeList.push(temp.val);
            temp=temp.next;
        }
        while (head!=null){
            if (head.val != stackNodeList.pop()){
                return false;
            }
            head=head.next;
        }
        return true;
    }

3.1合并两个有序单链表

思路:遍历两个链表的节点值,一次对比取出较小的节点接入新链表......

 public NodeList mergeOrderNodeLists(NodeList headA,NodeList headB){
        //创建一个虚拟头节点,用于指向合并后的新链表
        NodeList nodeListHead = new NodeList(0);
        NodeList head =nodeListHead;
        //遍历A,B链表
        while (headA!=null && headB!=null){
            //判断AB链表节点的值
            if (headA.val<=headB.val){
                head.next=headA;
                headA=headA.next;
            }else {
                head.next=headB;
                headB=headB.next;
            }
            return head;
        }
        //若有一方链表为空,直接把该链表接入nodeListHead后面
            head.next = headA == null ? headB : headA ;
       return head;
    }

3.2合并K个有序链表

思路:在合并两个有序链表的情况下,采用递归的方法

public NodeList mergeManyNodeList(NodeList[] manyNodeLists){
        //定义合并后的新链表
        NodeList newNodeList = null;
        //遍历链表集合,并递归合并两个有序链表
        for (NodeList nodeList:manyNodeLists){
            newNodeList = mergeOrderNodeLists(newNodeList, nodeList);
        }
        return newNodeList;
    }

3.3链表A区间删除,并在删除区间拼接链表B

题意:给定一个链表A,链表B,将链表A的下标I至J位置的节点删除,并拼接上链表

思路:遍历要删除的链表A,找到要删除节点I的前一个节点preNode,要删除节点J的后一个节点afterNode ;遍历B链表,找到B链表的尾节点 endB

preNode.next = B;
//B链表的尾节点 与 A链表删除后的后半部分 连接
endB.next = afterNode;

4.1.双指针

给定一个链表,返回中间节点,若改链表是偶数链节点,返回中间节点的第二个

例如 1-2-3-4 返回 3

 public NodeList findMiddleNodeList(NodeList head){
        //定义两个指针,快慢指针
        NodeList slow= head;
        NodeList fast =head;
        //当快指针达到链表末尾,慢指针一定处于链表中间位置
        // while条件中跳出循环:快指针的下一个节点为空,此时偶数节点链表会返回中间节点的第二个
        // 如果条件是 fast.next.next != null,偶数节点链表会返回中间节点的第一个
        while (fast!=null && fast.next !=null){
            slow=slow.next;
            fast=fast.next.next;
        }
        return slow;
    }

4.2返回链表倒数第K个节点

思路:定义快慢指针,刚开始让快指针与满指针间隔K个节点,当快指针走到链表尾部空节点,慢指针刚到走到倒数第K个节点

public NodeList countdown_K_NodeList(NodeList head,int key){
        //定义快慢节点
        NodeList fast = head;
        NodeList slow = head;
        //把快节点先前进k+1
        while (fast!=null && key>0){
            fast=fast.next;
            key--;
        }
        //判断fast节点是否到达链表尾部空节点处
        while (fast!=null){
            slow=slow.next;
            fast=fast.next;
        }
        return slow;
    }

4.3旋转链表

5.1删除链表特定节点

思路:定义一个虚拟节点(0),此时不用单独考虑首节点删除的情况

遍历链表,当链表的当前节点的next节点的val值=要删除的val,把当前节点的next值指向当前节点的next节点的next节点

public NodeList deleteByVal(NodeList head,int val){
        //创建一个虚拟节点,它的next指向head,此时不用单独考虑删除首节点情况
        NodeList virtuallyHead =new NodeList(0);
        virtuallyHead.next = head ;
        //当前节点curNode
        NodeList curNode = virtuallyHead;
        //遍历链表
        while (curNode.next!=null){
            if (curNode.next.val == val){
                curNode.next=curNode.next.next;
                curNode=curNode.next;
            }else {
                curNode=curNode.next;
            }
        }
        return virtuallyHead;
    }

5.2删除倒数第n个节点

方法一:遍历链表,找到要删除节点的前一个节点,并将要删除节点的前一个节点 的 next 指向

要删除节点的前一个节点 的 next.next节点...

   public NodeList removeNthFromEnd(NodeList head,int k){
        //定义虚拟节点
        NodeList dummy = new NodeList(0);
        dummy.next = head ;
        //获取链表的长度 调用getLengthNodeList():自编获取单链表长度的方法
        int length = getLengthNodeList(head);
        //找到要删除节点的前一个节点 curNode
        NodeList curNode = dummy;
        for (int i = 1 ;i<length - k +1 ;++i){
            curNode=curNode.next;
        }
        curNode.next = curNode.next.next;
        NodeList result = dummy.next;
        return result;
    }

    //获取链表长度
    public int getLengthNodeList(NodeList head){
        int length = 0 ;
        while (head!=null){
            length=length+1;
            head=head.next;
        }
        return length;
    }

方法二:双指针法

思路:first指针先前进k步,然后first指针和second指针同时前进,当first指针的下一个指针为空,

second指针的下一个节点即是要删除的节点

 public NodeList removeNthFromEnd(NodeList head,int k){
        //定义虚拟节点
        NodeList dummy = new NodeList(0);
        dummy.next=head;
        NodeList first = dummy.next;
        NodeList second =dummy;
        //同步走前,first比second提前走k
        for (int i =0;i<k;++i){
             first=first.next;
        }
        //first,second同步走
        while (first!=null){
            first=first.next;
            second=second.next;
        }
        //跳出循环,此处second是删除节点的前一个节点
        second.next =second.next.next;
        NodeList result = dummy.next;
        return result;
    }

5.3删除重复元素(给定链表有序的)

5.3.1重复元素保留一个

遍历链表,如果当前节点 与 当前节点的下一个 节点 相等,把当前节点的next指针 指向 当前节点的next的next节点(即删除了当前节点的下一个节点)

  public NodeList deleteEqualNodeList(NodeList head) {
        if (head == null) {
            return head;
        }
        NodeList curNode = head;
        //循环遍历链表
        while (curNode.next != null) {
            if (curNode.val == curNode.next.val) {
                curNode.next = curNode.next.next;
            } else {
                curNode = curNode.next;
            }
        }
        return head;
    }

5.3.2重复元素都删除

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值