本文参考自《剑指offer》一书,代码采用Java语言。

更多:《剑指Offer》Java实现合集  

题目

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

思路

  通常那样从头开始查找删除需要的时间为O(n),要在O(1)时间删除某结点,可以这样实现:设待删除结点i的下一个结点为j,把j的值复制到i,再把i的指针指向j的下一个结点,最后删除j,效果就相当于删除j。

  注意特殊情况:1.当待删除结点i为尾结点时,无下一个结点,则只能从头到尾顺序遍历;2.当链表中只有一个结点时(即是头结点,又是尾结点),必须把头结点也设置为null。

  本题有个缺陷:要求O(1)时间删除,相当于隐藏了一个假设:待删除的结点的确在表中

测试算例

  1.功能测试(多个结点链表,删除头结点、中间结点和尾结点;单个结点链表)

  2.特殊测试(头结点或删除结点为null)

完整Java代码

(含测试代码)

  1. package _18;
  2. /**
  3. *
  4. * @Description 面试题18(一):在O(1)时间删除链表结点
  5. *
  6. * @author yongh
  7. * @date 2018年9月18日 下午3:57:59
  8. */
  9.  
  10. //题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该
  11. //结点。
  12.  
  13. //注:本题存在缺陷,要求O(1)时间,则无法确定待删除结点的确在表中
  14.  
  15. public class DeleteNodeInList {
  16. public class ListNode{
  17. int val;
  18. ListNode next;
  19. public ListNode(int value,ListNode nextNode) {
  20. val=value;
  21. next=nextNode;
  22. }
  23. }
  24.  
  25. /**
  26. * 返回值:头结点
  27. * 返回值不可以为void,否则头结点无法删除
  28. * 即:函数中虽然令head=null,但返回到主程序后,
  29. * head还是不变,所以令该函数返回值为ListNode
  30. */
  31. public ListNode deleteNode(ListNode head,ListNode pToBeDeleted) {
  32. if(head==null||pToBeDeleted==null)
  33. return head;
  34. //待删除结点不是尾结点
  35. if(pToBeDeleted.next!=null) {
  36. ListNode nextNode=pToBeDeleted.next;
  37. pToBeDeleted.val=nextNode.val;
  38. pToBeDeleted.next=nextNode.next;
  39. nextNode=null;
  40. //只有一个结点(即是尾结点,又是头结点)
  41. }else if(head==pToBeDeleted) {
  42. pToBeDeleted=null;
  43. head=null;
  44. //链表含多个结点,删除尾结点
  45. }else {
  46. ListNode preNode=head;
  47. while(preNode.next!=pToBeDeleted && preNode!=null) {
  48. preNode=preNode.next;
  49. }
  50. if(preNode==null) {
  51. System.out.println("无法找到待删除结点!");
  52. return head;
  53. }
  54. preNode.next=null;
  55. pToBeDeleted=null;
  56. }
  57. return head;
  58. }
  59.  
  60. //=========测试代码==========
  61. void test(ListNode head,ListNode PToBeDelete) {
  62. System.out.println("============");
  63. System.out.print("The original list is: ");
  64. ListNode curr=head;
  65. if(curr!=null) {
  66. while(curr.next!=null) {
  67. System.out.print(curr.val+",");
  68. curr=curr.next;
  69. }
  70. System.out.println(curr.val);
  71. }else {
  72. System.out.println();
  73. }
  74.  
  75. System.out.print("The node to be deleted is: ");
  76. if(PToBeDelete!=null)
  77. System.out.println(PToBeDelete.val);
  78. else
  79. System.out.println();
  80.  
  81. curr=deleteNode(head, PToBeDelete);
  82. System.out.print("The result list is: ");
  83. if(curr!=null) {
  84. while(curr.next!=null) {
  85. System.out.print(curr.val+",");
  86. curr=curr.next;
  87. }
  88. System.out.println(curr.val);
  89. }else {
  90. System.out.println();
  91. }
  92. System.out.println("============");
  93. }
  94.  
  95. /**
  96. * 链表含多个结点,删除头结点
  97. */
  98. void test1() {
  99. ListNode p4=new ListNode(4, null);
  100. ListNode p3=new ListNode(3, p4);
  101. ListNode p2=new ListNode(2, p3);
  102. ListNode p1=new ListNode(1, p2);
  103. test(p1, p1);
  104. }
  105.  
  106. /**
  107. * 链表含多个结点,删除中间结点
  108. */
  109. void test2() {
  110. ListNode p4=new ListNode(4, null);
  111. ListNode p3=new ListNode(3, p4);
  112. ListNode p2=new ListNode(2, p3);
  113. ListNode p1=new ListNode(1, p2);
  114. test(p1, p3);
  115. }
  116.  
  117. /**
  118. * 链表含多个结点,删除尾结点
  119. */
  120. void test3() {
  121. ListNode p4=new ListNode(4, null);
  122. ListNode p3=new ListNode(3, p4);
  123. ListNode p2=new ListNode(2, p3);
  124. ListNode p1=new ListNode(1, p2);
  125. test(p1, p4);
  126. }
  127.  
  128. /**
  129. * 链表含一个结点,删除结点
  130. */
  131. void test4() {
  132. ListNode p4=new ListNode(4, null);
  133. test(p4, p4);
  134. }
  135.  
  136. /**
  137. * 链表为空
  138. */
  139. void test5() {
  140. test(null, null);
  141. }
  142.  
  143. public static void main(String[] args) {
  144. DeleteNodeInList demo = new DeleteNodeInList();
  145. demo.test1();
  146. demo.test2();
  147. demo.test3();
  148. demo.test4();
  149. demo.test5();
  150. }
  151. }

  

  1. ============
  2. The original list is: ,,,
  3. The node to be deleted is:
  4. The result list is: ,,
  5. ============
  6. ============
  7. The original list is: ,,,
  8. The node to be deleted is:
  9. The result list is: ,,
  10. ============
  11. ============
  12. The original list is: ,,,
  13. The node to be deleted is:
  14. The result list is: ,,
  15. ============
  16. ============
  17. The original list is:
  18. The node to be deleted is:
  19. The result list is:
  20. ============
  21. ============
  22. The original list is:
  23. The node to be deleted is:
  24. The result list is:
  25. ============

DeleteNodeInList

收获

  1.链表中删除结点的方法中,虽然直接令head=null了,但在主函数中的head还是不变,因此要令删除结点的返回值为ListNode,将返回值赋值给主函数中的head,这样才能实现真正的删除。

  2.另一种情况可以令删除函数返回值为void,只是需要定义一个头结点head(1中的head相当于是第一个结点),这个头结点中不存任何数据,仅仅起到指针的作用,第一个结点是头结点的下一个结点,通过对head.next操作,能够实现真正的删除。

  3.和链表有关的特殊情况:头结点,尾结点,链表仅一个结点,null等。

更多:《剑指Offer》Java实现合集  

【Java】 剑指offer(17) 在O(1)时间删除链表结点的更多相关文章

  1. 剑指offer 17:合并两个有序链表

    题目描述 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则.   解题思路 链表基础操作考察,难点在于对于输入数据的把握,一定要考虑输入数据的全面性 1.出现 ...

  2. (剑指Offer)面试题57:删除链表中的重复结点

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

  3. 剑指offer——面试题18.1:删除链表中重复的节点

    // 面试题18(二):删除链表中重复的结点 // 题目:在一个排序的链表中,如何删除重复的结点?例如,在图3.4(a)中重复 // 结点被删除之后,链表如图3.4(b)所示. #include &l ...

  4. 剑指 Offer 17. 打印从1到最大的n位数

    剑指 Offer 17. 打印从1到最大的n位数 Offer 17 题目解析: 暴力解法 package com.walegarrett.offer; /** * @Author WaleGarret ...

  5. 力扣 - 剑指 Offer 17. 打印从1到最大的n位数

    题目 剑指 Offer 17. 打印从1到最大的n位数 思路1 如果有n位,那么最大值就是\(10^n-1\),即如果n是2,那么最大就到输出到99 考虑到大数情况,所以使用字符数组 还要把字符数组转 ...

  6. 剑指Offer:合并两个排序的链表【25】

    剑指Offer:合并两个排序的链表[25] 题目描述 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. 题目分析 每次都是比较箭头节点,把小节点连接到已经合 ...

  7. 《剑指offer》 合并两个排序的链表

    本题来自<剑指offer> 合并两个排序的链表 题目: 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. 思路: A:采用递归的方式(C++ C ...

  8. 剑指 Offer 25. 合并两个排序的链表

    剑指 Offer 25. 合并两个排序的链表 Offer 25 该问题的原型就是多项式的合并. 实现较简单,没有特殊需要注意的问题. package com.walegarrett.offer; /* ...

  9. 【剑指Offer】合并两个排序的链表 解题报告(Python)

    [剑指Offer]合并两个排序的链表 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://www.nowcoder.com/ta/coding-interview ...

随机推荐

  1. golang error信息转字符串 x := fmt.Sprintf("%s", err)

    _, _, ch, err := m.ZkConn.ChildrenW(node) if err != nil { x := fmt.Sprintf("%s", err) if s ...

  2. Java基础编程题——分别统计出其中汉字、英文字母、空格、数字和其它字符的个数

    package com.yangzl.basic; import java.util.Scanner; /** * 分别统计出其中汉字.英文字母.空格.数字和其它字符的个数 * @author Adm ...

  3. linux 网卡

    查看网卡UUID:nmcli con show    或    nmcli con list 查看网卡mac地址:nmcli dev show    或    nmcli dev list 注:sho ...

  4. 第一个FPGA工程—LED流水灯

    这一章我们来实现第一个FPGA工程-LED流水灯.我们将通过流水灯例程向大家介绍一次完整的FPGA开发流程,从新建工程,代码设计,综合实现,管脚约束,下载FPGA程序.掌握本章内容,大家就算正式的开始 ...

  5. mysql caching_sha2_password异常分析

    使用navicat连接mysql报错 解决办法: 通过命令行登录mysql后,输入: alter user 'root'@'localhost' IDENTIFIED WITH mysql_nativ ...

  6. 使用ajax上传表单(带文件)

    在使用form表单的时候上传文件+表单,会使得页面跳转,而在某些时候不希望跳转,只变化页面中的局部信息 通过查找资料,可以使用FormData进行ajax操作. FormData介绍:XMLHttpR ...

  7. shell脚本收集服务器基本信息并入库

    # cat check_all.sh #!/bin/bash #create by hexm @2016.6 #date=`date +%Y%m%d` #DIST_FILE=/app/healthch ...

  8. [学习笔记]JS 数组Array push相关问题

    前言: 今天用写了一个二维数组,都赋值为零,然后更新其中一个值,结果和预期是不一样,会整列的相同位置都是同一个值. 1.用Chrome的控制台样例如下: arrs[2][2] =1的赋值,竟然是三个数 ...

  9. JavaScript中的事件冒泡?事件传播的解释

    注:本文来源  可译网 事件冒泡是你在学习javaScript旅途中遇到的一个术语,它涉及到当一个元素被另一个元素嵌套时调用事件处理的顺序,并且两个元素注册了同一个事件(例如,点击事件). 但是事件冒 ...

  10. python3之MongoDB

    1.MongoDB简介 MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统. 在高负载的情况下,添加更多的节点,可以保证服务器性能. MongoDB 旨在为WEB应用提供可 ...