剑指Offer——题18(在 O(1) 时间内删除链表节点、删除链表中重复的节点)

1.1题目

在 O(1) 时间内删除链表节点

 给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。

1.2.思路

在单向链表中,因为我们需要得到被删除节点的前一个节点,常规思维是从头节点开始遍历需要删除的节点,需要的时间是O(n),

也可以这样实现:我们要删除节点i,先把i的下一个节点的内容复制到j,然后把i的指针指向j的下一个节点,这时再删除结点j,就相当于删除了节点i。

注意:

  • 当删除的节点i既是头结点也是尾结点,即只有一个节点时,必须把头结点也设置为null
  • 当删除节点i为尾结点时,无下一个节点只能从头到尾顺序遍历
  • 本题有个缺陷:相当于隐藏了一个假设:待删除的节点的确在表中。
  • 引用类型传参,方法返回类型不可以为void,否则无法删除头结点

1.3.代码实现

public class DeleteNode {
    class ListNode{
        int val;
        ListNode next;

        public ListNode(int val, ListNode next) {
            this.val = val;
            this.next = next;
        }
    }

    public ListNode deleteNode(ListNode head,ListNode deleteNode){


        if(head==null||deleteNode==null){
            return head;
        }
        //删除的节点不是尾结点(其他节点和头结点)
        if(deleteNode.next!=null){
            deleteNode.val=deleteNode.next.val;
            deleteNode.next=deleteNode.next.next;
        } else if(deleteNode==head){
            //删除只有一个节点(即头尾节点相同)
            head=null;
        } else{
            //2.删除尾结点
            ListNode pNode=head;
            while(pNode.next!=deleteNode){
                pNode=pNode.next;
            }
            pNode.next=null;
        }
//这里返回值不能为void,否则无法删除头结点
        return head;
    }


    public void test(ListNode head,ListNode deleteNode){
        System.out.println("The original list is:");
        ListNode currentNode=head;
        if(currentNode!=null){
            while (currentNode.next!=null){
                System.out.print(currentNode.val+",");
                currentNode=currentNode.next;
            }
            System.out.println(currentNode.val);
        }

        System.out.println("The node to be delete is:");
        if(deleteNode!=null){
            System.out.println(deleteNode.val);
        }
        System.out.println("The result list is:");

        currentNode=deleteNode(head,deleteNode);
        if(currentNode!=null){
            while (currentNode.next!=null){
                System.out.print(currentNode.val+",");
                currentNode=currentNode.next;
            }
            System.out.println(currentNode.val);
        }else {
            System.out.println("null");
        }
    }

    //删除头结点
    @Test
    public void test1(){
        ListNode node4=new ListNode(4,null);
        ListNode node3=new ListNode(3,node4);
        ListNode node2=new ListNode(2,node3);
        ListNode node1=new ListNode(1,node2);
        test(node1,node1);
    }

   //删除的不是尾结点
    @Test
    public void test2(){
        ListNode node4=new ListNode(4,null);
        ListNode node3=new ListNode(3,node4);
        ListNode node2=new ListNode(2,node3);
        ListNode node1=new ListNode(1,node2);
        test(node1,node3);

    }

//删除尾结点
    @Test
    public void test3(){
        ListNode node4=new ListNode(4,null);
        ListNode node3=new ListNode(3,node4);
        ListNode node2=new ListNode(2,node3);
        ListNode node1=new ListNode(1,node2);
        test(node1,node4);
    }
    //只有一个节点尾结点
    @Test
    public void test4(){
        ListNode node4=new ListNode(4,null);
        ListNode head=deleteNode(node4,node4);
        test(node4,node4);

    }

}

2.题目2

【题目】:在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

【思路】:

如果当前节点的值与下一个节点的值相同,那么它们就是重复的节点,都可以被删除。为了保证删除之后的链表仍然是相连的,我们要从当前节点要删除的节点继续遍历。我们要确保前一个始终与下一个没有重复的节点连接在一起。
 

public class DeleteDuplication {

    class ListNode{
        int val;
        ListNode next;


        public ListNode(int val, ListNode next) {
            this.val = val;
            this.next = next;
        }
    }

    public ListNode deleteDuplication(ListNode pHead)
    {
        if(pHead==null){
           return pHead;
        }

        ListNode curNode=pHead;
        ListNode preNode=null;

        while(curNode!=null){

           boolean needDel=false;
           if(curNode.next!=null&&curNode.val==curNode.next.val){   //节点重复,标志位false
               needDel=true;
           }
           //节点不重复
           if(!needDel){
               preNode=curNode;
               curNode=curNode.next;
           }else{
            //节点重复,进行删除操作
               ListNode delNode=curNode;
              while(delNode!=null&&delNode.val==curNode.val){
                  delNode=delNode.next;
              }
              //删除的节点是头结点
               if(preNode==null){
                   pHead=delNode;
               }else{
                   preNode.next=delNode;
               }
               //当前节点也可能和后面的节点重复
               curNode=delNode;
           }
       }
        return pHead;
       }

@Test
    public  void test() {
        ListNode node6=new ListNode(6,null);
        ListNode node5=new ListNode(5,node6);
        ListNode node4=new ListNode(3,node5);
        ListNode node3=new ListNode(3,node4);
        ListNode node2=new ListNode(2,node3);
        ListNode node1=new ListNode(1,node2);

        ListNode curNode=deleteDuplication(node1);
        while(curNode!=null){
            System.out.println(curNode.val);
            curNode=curNode.next;
        }
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值