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;
}
}
}