每天一道算法题--单链表的相关操作

单链表在笔试面试中属于重点考察对象,这里总结几个常考的单链表操作。

//构造链表结构
    static class ListNode {
          int val;
          ListNode next;
          ListNode(int x) { val = x; }
    }
  • 删除单链表中的某一结点(不是从前一节点删除后一节点)
    这里写图片描述

删除节点,此时这里给出的节点正是将删除节点,而且是单链表(注意尾节点的处理)
这里是是下一个节点的值直接付给要删除的节点,然后删除下一个节点即可


     public static void deleteNode(ListNode node) {
            if(node.next==null){
                node=null;
             }else{
                 node.val=node.next.val;
                 node.next=node.next.next; 
             }
     }
  • 删除链表中值为val的节点

删除值为val的节点,一般遇到这种要注意头节点是否会改变年,如果改变需要将头节点先储存起来

public static ListNode removeElements(ListNode head, int val) {
         if(head==null) return null;
         ListNode node=head;
         //先判断下一个节点是否为空
         while(node.next!=null){
             if(node.next.val==val){
                 node.next=node.next.next;
             }else{
                 //注意这里替换使用当前结点替换下一个节点
                 node=node.next;
             }
         }
        //把头节点放到最后一个判断
         if(head.val==val){
             head=head.next;
         }
         return head;

    }
  • 删除链表中倒数第n个节点

因为在链表长度是不可知的,因此可以多创建一个指针来进行标记。即当一个指针只想被删除节点时,另外一个指针指向最后一个节点,期间相距n-1个节点。 但实际上这里设计的时候使两个指针相隔n个节点,以便通过前节点将后节点删除,而且注意这里可能会改变头节点,因此要保留头节点

 public static ListNode removeNthFromEnd(ListNode head, int n) {
         if(head==null) return null;
          ListNode dummy = new ListNode(0);
          dummy.next = head;
          ListNode lastNode = dummy;
          ListNode headNode = dummy;
          for (int i = 1; i <= n + 1; i++) {
              lastNode = lastNode.next;
            }
            while (lastNode != null) {
                lastNode = lastNode.next;
                headNode = headNode.next;
            }
            headNode.next = headNode.next.next;
            return dummy.next;

     }
  • 在有序链表中删除重复的节点,但保留第一个重复的点

两个相邻的指针同时出发,当值不同时,都往前移动,当值相同时,则前指针不移动,后指针移动(腾讯有一道笔试题与此类似:找出红包金额出线数过半的金额数)

 public static  ListNode deleteDuplicates(ListNode head) {
         if(head==null) return null;
         ListNode lastNode =head.next;
         ListNode headNode =head;
         while(lastNode!=null){
             if(headNode.val==lastNode.val){
                 lastNode=lastNode.next;
                 headNode.next=lastNode;
             }else{
                 headNode=headNode.next;
                 lastNode=lastNode.next;
             }
         }
         return head;
     }

以上这道题有一道变形题,在有序链表中删除节点,但是所有重复节点都不保留,因此可能会改变头节点,因此需要对头节点进行数据备份

public static ListNode deleteDuplicates2(ListNode head) {
         if(head==null) return null;
         ListNode dummy = new ListNode(-1);
         dummy.next = head;
         ListNode lastNode =dummy.next;
         ListNode headNode =dummy;
         //全都是对下一个数据进行比较
         while(lastNode.next!=null){
             if(lastNode.next.val==headNode.next.val){
                 //比如链表如右:1234444567,出现重复后,headNode停在第一个4的位置前面,下一个指针遍历到最后一个4的位置上
                 //在改变头节点时,尤其是已经有其他节点保存了头节点,需要借助指针的方式来改变,不可以改变内存地址的形式实现
                //如果下一个节点还是值相等,则往后移一个节点
                 while(lastNode.next.val==headNode.next.val&&lastNode.next.next!=null&&lastNode.next.next.val==headNode.next.val){
                     lastNode=lastNode.next;
                 }
                 //这里要删除中间相同的n多个节点,此时headNode停在第一个4的位置前面(3),下一个指针遍历到最后一个4的位置上
                 //注意要把两个节点所在的节点一起删去
                 if(lastNode.next.next!=null){
                     headNode.next=lastNode.next.next;
                     if(lastNode.next.next.next!=null){
                         lastNode.next=lastNode.next.next.next;
                     }else{
                         lastNode.next=null;
                     }
                 }else{
                     lastNode.next=null;
                     headNode.next=lastNode.next;
                 }
             }else{
                 headNode=headNode.next;
                 lastNode=lastNode.next;
             }
         }
         return dummy.next;
     }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值