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

来源:互联网 发布:长沙黑马程序员 编辑:程序博客网 时间:2024/06/07 19:58

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

//构造链表结构    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;     }