本文参考自《剑指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代码

(含测试代码)

package _18;
/**
*
* @Description 面试题18(一):在O(1)时间删除链表结点
*
* @author yongh
* @date 2018年9月18日 下午3:57:59
*/ //题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该
//结点。 //注:本题存在缺陷,要求O(1)时间,则无法确定待删除结点的确在表中 public class DeleteNodeInList {
public class ListNode{
int val;
ListNode next;
public ListNode(int value,ListNode nextNode) {
val=value;
next=nextNode;
}
} /**
* 返回值:头结点
* 返回值不可以为void,否则头结点无法删除
* 即:函数中虽然令head=null,但返回到主程序后,
* head还是不变,所以令该函数返回值为ListNode
*/
public ListNode deleteNode(ListNode head,ListNode pToBeDeleted) {
if(head==null||pToBeDeleted==null)
return head;
//待删除结点不是尾结点
if(pToBeDeleted.next!=null) {
ListNode nextNode=pToBeDeleted.next;
pToBeDeleted.val=nextNode.val;
pToBeDeleted.next=nextNode.next;
nextNode=null;
//只有一个结点(即是尾结点,又是头结点)
}else if(head==pToBeDeleted) {
pToBeDeleted=null;
head=null;
//链表含多个结点,删除尾结点
}else {
ListNode preNode=head;
while(preNode.next!=pToBeDeleted && preNode!=null) {
preNode=preNode.next;
}
if(preNode==null) {
System.out.println("无法找到待删除结点!");
return head;
}
preNode.next=null;
pToBeDeleted=null;
}
return head;
} //=========测试代码==========
void test(ListNode head,ListNode PToBeDelete) {
System.out.println("============");
System.out.print("The original list is: ");
ListNode curr=head;
if(curr!=null) {
while(curr.next!=null) {
System.out.print(curr.val+",");
curr=curr.next;
}
System.out.println(curr.val);
}else {
System.out.println();
} System.out.print("The node to be deleted is: ");
if(PToBeDelete!=null)
System.out.println(PToBeDelete.val);
else
System.out.println(); curr=deleteNode(head, PToBeDelete);
System.out.print("The result list is: ");
if(curr!=null) {
while(curr.next!=null) {
System.out.print(curr.val+",");
curr=curr.next;
}
System.out.println(curr.val);
}else {
System.out.println();
}
System.out.println("============");
} /**
* 链表含多个结点,删除头结点
*/
void test1() {
ListNode p4=new ListNode(4, null);
ListNode p3=new ListNode(3, p4);
ListNode p2=new ListNode(2, p3);
ListNode p1=new ListNode(1, p2);
test(p1, p1);
} /**
* 链表含多个结点,删除中间结点
*/
void test2() {
ListNode p4=new ListNode(4, null);
ListNode p3=new ListNode(3, p4);
ListNode p2=new ListNode(2, p3);
ListNode p1=new ListNode(1, p2);
test(p1, p3);
} /**
* 链表含多个结点,删除尾结点
*/
void test3() {
ListNode p4=new ListNode(4, null);
ListNode p3=new ListNode(3, p4);
ListNode p2=new ListNode(2, p3);
ListNode p1=new ListNode(1, p2);
test(p1, p4);
} /**
* 链表含一个结点,删除结点
*/
void test4() {
ListNode p4=new ListNode(4, null);
test(p4, p4);
} /**
* 链表为空
*/
void test5() {
test(null, null);
} public static void main(String[] args) {
DeleteNodeInList demo = new DeleteNodeInList();
demo.test1();
demo.test2();
demo.test3();
demo.test4();
demo.test5();
}
}

  

============
The original list is: ,,,
The node to be deleted is:
The result list is: ,,
============
============
The original list is: ,,,
The node to be deleted is:
The result list is: ,,
============
============
The original list is: ,,,
The node to be deleted is:
The result list is: ,,
============
============
The original list is:
The node to be deleted is:
The result list is:
============
============
The original list is:
The node to be deleted is:
The result list is:
============

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. Json Schema简介

    1. 引言 什么是Json Schema? 以一个例子来说明 假设有一个web api,接受一个json请求,返回某个用户在某个城市关系最近的若干个好友.一个请求的例子如下: { "city ...

  2. HDU4635 Strongly connected【强连通】

    题意: 给一个n个点的简单有向图,问最多能加多少条边使得该图仍然是简单有向图,且不是强连通图.简单有向图的定义为:没有重边,无自环. 强连通图的定义为:整个图缩点后就只有一个点,里面包含n个原点,也就 ...

  3. 第5月第6天 NSOperation isConcurrent category同名覆盖

    1. @implementation AFURLConnectionOperation ... - (BOOL)isConcurrent { return YES; } NSOperation调用st ...

  4. pycharm永久激活(转)

    机器上安装的pycharm失效了,注册服务器也不管用了.网上找了一个比较满意的激活方法,推荐给大家: 第一步:下载jar包: 此jar包的目的就是让截获截止时间并骗过pycharm; 百度云下载地址  ...

  5. Sqoop入门

    1 下载地址         http://archive.cloudera.com/cdh5/cdh/5/         版本 sqoop-1.4.6-cdh5.7.0         安装包   ...

  6. Python(十三)python的函数重载

    首先,重载函数的功能是实现参数不同情况下功能相同的函数. 函数重载的目的是解决功能相同的函数的以下问题: 1.参数的类型: 2.参数的个数: 对于情况1,函数功能呢相同,参数不同的情况. python ...

  7. mysql 案例 ~ pt-xtrabackup 使用

    一 简介:学习innobackup工具使用 二 功能: 备份全库/单库/单表 三 常用命令  一 全库  目的 每天日常备份  备份 innobackupex --defaults-file=/etc ...

  8. Android Retrofit 2.0使用

    实例带你了解Retrofit 2.0的使用,分享目前开发Retrofit遇到的坑和心得. 添加依赖 app/build.gradle 1 compile 'com.squareup.retrofit2 ...

  9. 【黑客免杀攻防】读书笔记5 - PE格式讲解

    0x01 MS-DOS头 MS-DOS头部的字段重点关注e_magic与最后一个e_lfanew是需要关注的. 第一个e_magic字段的值为4D5A,作用是可以作为判断这个文件是否是PE文件. 最后 ...

  10. xargs -i和-I的区别【转】

    xargs与find经常结合来进行文件操作,平时删日志的时候只是习惯的去删除,比如  # find . -type f -name "*.log" | xargs rm -rf * ...