【题一】在 O(1) 时间内删除链表节点
【题目】:
给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。
【思路】:
常规思维是从头开始顺序查找需要删除的节点,需要的时间为O(n)。
要在O(1)时间删除某结点,可以这样实现:设待删除结点 i 的下一个结点为 j,把 j 的值复制到 i ,再把 i 的指针指向 j 的下一个结点,最后删除 j,效果就相当于删除j。
注意特殊情况:1.当待删除结点 i 为尾结点时,无下一个结点,则只能从头到尾顺序遍历;2.当链表中只有一个结点时(即是头结点,又是尾结点),必须把头结点也设置为null。
本题有个缺陷:要求O(1)时间删除,相当于隐藏了一个假设:待删除的结点的确在表中
package com.offer.offer18;
/**
* @author zth
* @Date 2019-08-10 10:01
*/
class ListNode{
int val;
ListNode next;
public ListNode(int value,ListNode nextNode) {
val=value;
next=nextNode;
}
}
public class DeleteNodeInList {
/**
*
* @param head 链表头指针
* @param pToBeDeleted 待删除节点
* @return 返回头指针,如果返回 void ,将无法删除头结点
*
*/
public ListNode deleteNode(ListNode head, ListNode pToBeDeleted) {
if (null == head || null == pToBeDeleted){
return head;
}
// 要删除的节点不是尾节点
if (pToBeDeleted.next != null){
// 待删除节点失去引用变为可回收对象
pToBeDeleted.val = pToBeDeleted.next.val;
pToBeDeleted.next = pToBeDeleted.next.next;
}else if (pToBeDeleted == head){
head = null;
pToBeDeleted = null;
}else {
// 链表有多个节点,删除尾节点
// 需要从链表的头开始,顺序遍历得到该节点的前序节点,完成删除。
ListNode pNode = head;
while (pNode.next != pToBeDeleted){
pNode = pNode.next;
}
pNode.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();
System.out.print("The result list is: ");
curr=deleteNode(head, PToBeDelete);
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();
}
}
【题二】删除链表中重复的节点
【题目】:在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
【思路】:
如果当前节点的值与下一个节点的值相同,那么它们就是重复的节点,都可以被删除。为了保证删除之后的链表仍然是相连的,我们要把当前节点的前一个节点和后面值比当前节点的值大的节点相连。我们要确保前一个始终与下一个没有重复的节点连接在一起。
package com.offer.offer18;
/**
* @author zth
* @Date 2019-08-10 11:29
* 删除链表中重复元素,返回头节点
*/
public class DeleteDuplication {
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
public ListNode deleteDuplication(ListNode pHead){
// 链表为空或只有一个节点
if (null== pHead || null == pHead.next){
return pHead;
}
ListNode curNode = pHead;
ListNode preNode = null;
while (curNode != null){
boolean needDel = false;
if (curNode.next!=null && curNode.val == curNode.next.val){
needDel = true;
}
if (!needDel){
// 当前节点不重复
preNode = curNode;
curNode = curNode.next;
}else {
// 当前节点重复
ListNode toBeDel = curNode;
while (toBeDel != null && toBeDel.val==curNode.val){
toBeDel = toBeDel.next;
}
if (preNode == null){
// 删除的节点为头结点
pHead = toBeDel;
}else {
preNode.next = toBeDel;
}
// 该节点也会出现重复
curNode = toBeDel;
}
}
return pHead;
}
//========测试代码======
void test(ListNode pHead) {
System.out.println("-----------");
System.out.print("The original list is: ");
ListNode curr=pHead;
if(curr!=null) {
while(curr.next!=null) {
System.out.print(curr.val+",");
curr=curr.next;
}
System.out.println(curr.val);
}else {
System.out.println();
}
pHead=deleteDuplication(pHead);
System.out.print("The result list is: ");
curr=pHead;
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(3, null);
ListNode p3=new ListNode(2, p4);
ListNode p2=new ListNode(1, p3);
ListNode p1=new ListNode(1, p2);
test(p1);
}
/**
* 重复结点位于链表尾部
*/
void test2() {
ListNode p4=new ListNode(3, null);
ListNode p3=new ListNode(3, p4);
ListNode p2=new ListNode(2, p3);
ListNode p1=new ListNode(1, p2);
test(p1);
}
/**
* 重复结点位于链表中部
*/
void test3() {
ListNode p4=new ListNode(3, null);
ListNode p3=new ListNode(2, p4);
ListNode p2=new ListNode(2, p3);
ListNode p1=new ListNode(1, p2);
test(p1);
}
/**
* 连续出现重复结点
*/
void test4() {
ListNode p6=new ListNode(3, null);
ListNode p5=new ListNode(3, p6);
ListNode p4=new ListNode(2, p5);
ListNode p3=new ListNode(2, p4);
ListNode p2=new ListNode(1, p3);
ListNode p1=new ListNode(1, p2);
test(p1);
}
/**
* 多个重复结点
*/
void test5() {
ListNode p6=new ListNode(3, null);
ListNode p5=new ListNode(3, p6);
ListNode p4=new ListNode(3, p5);
ListNode p3=new ListNode(2, p4);
ListNode p2=new ListNode(1, p3);
ListNode p1=new ListNode(1, p2);
test(p1);
}
/**
* 无重复结点
*/
void test6() {
ListNode p6=new ListNode(6, null);
ListNode p5=new ListNode(5, p6);
ListNode p4=new ListNode(4, p5);
ListNode p3=new ListNode(3, p4);
ListNode p2=new ListNode(2, p3);
ListNode p1=new ListNode(1, p2);
test(p1);
}
/**
* 单个结点
*/
void test7() {
ListNode p1=new ListNode(6, null);
test(p1);
}
/**
* null
*/
void test8() {
ListNode p1=null;
test(p1);
}
public static void main(String[] args) {
DeleteDuplication demo= new DeleteDuplication();
demo.test1();
demo.test2();
demo.test3();
demo.test4();
demo.test5();
demo.test6();
demo.test7();
demo.test8();
}
}