1、 删除链表中等于给定值 “val” 的所有节点。
解题思路:先考虑特殊情况,当链表为空直接返回null,想要删除指定元素则需遍历一遍链表,从第二个节点开始遍历,如果从第一个节点开始遍历,第一个节点的prev会出现空指针异常,此时创建两个结点cur用于遍历和prev用于删除,如果cur的值等于val, 利用prev删除cur,如果cur的值不等于val,则cur、prev都向后走一步,最后再回过头来看head的值是否为val,最终返回链表头节点head。
public ListNode removeElements(LinkedNode head,int val){
if(head==null){
return null;
}
//1.先删非头结点
LinkedNode prev = head;
LinkedNode cur=head.next;
while(cur!=null){
if(cur.val==val){
//删除
prev.next=cur.next;
cur=prev.next;
}else{
//跳过
prev=cur;
cur=cur.next;
}
}
//2.再删头节点
if(head.val == val){
head=head.next;
}
return head;
}
2、反转一个单链表。
解题思路:首先考虑两种特殊情况,一是为空链表时,直接返回null即可,二是当链表中只含有一个元素时,不需要进行特殊处理返回head即可。下面处理普通情况,首先定义一个新结点newHead作为反转后链表的头结点,初始化为null,但不意味着指向null,再分别定义三个结点,cur指向头结点,prev初始化为空,next保存cur的下一个结点。
把当前对象cur的下一个指向prev,再将prev 赋值给cur,然后cur赋值为下一个对象next,即可完成反转操作,之后仅需循环重复该操作。
当next为空时意味着链表结束(cur.next == null),此时的cur为反转后链表的头结点即newHead,最终返回newHead得到反转后的单链表。
public ListNode reverseList(ListNode head){
if(head == null){//空链表
return null;
}
//对于只有一个元素的链表,不需要处理
if(head.next=null){
return head;
}
//处理多个元素情况
ListNode newHead=null;
ListNode cur=head;
ListNode prev=null;
while(cur!=null){
ListNode next=cur.next;
if(next==null){
newHead=cur;
}
//翻转指针指向
cur.next=prev;
prev=cur;
cur=next;
}
return newHead;
}
3、给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
解题思路:将头结点head传给size()函数,求得链表长度,定义变量steps为长度一半即steps=size(head)/2,创建一个新的结点指向头结点cur,利用for循环使cur向后走steps次,最后返回cur即为链表的中间结点。
public ListNode middleNode(ListNode head){
//1.得到链表长度
int steps = size(head)/2;
ListNode cur=head;
for(int i=0;i<steps;i++){
cur=cur.next;
}
return cur;
}
public int size(ListNode head){
int size =0;
for(ListNode cur = head;
cur != null;cur = cur.next){
size++;
}
return size;
}
4、输入一个链表,输出该链表中倒数第k个结点。
解题思路:此题与第三题求中间结点思路大致相同,但具体使cur向后移动的步数略有不同,求倒数第K个结点时,总长度减去k即为需要走的步长,最终依旧是返回cur,便可得到倒数第K个结点。
另:此类题若用C语言解决,可使用:“快慢指针”法,快指针先走K步,然后两个指针同时后移,当快指针到达终点时,则慢指针就处于倒数第K个结点位置处。如果是解决求中间结点位置,则让快指针一次走两步,慢指针一次走一步,最终快指针到达终点时,慢指针即处于链表的中间位置。
public ListNode FindKthToTail(ListNode head,int k){
int length=size(head);
if(head==null || k<=0 || k>length){
return null;
}
//总长度减去k即为需要走的步长
int offset=length-k;
ListNode cur=head;
for (int i = 0; i < offset; i++) {
cur=cur.next;
}
return cur;
}
public int size(ListNode head){
int size =0;
for(ListNode cur = head;
cur != null;cur = cur.next){
size++;
}
return size;
}
5、 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
解题思路:创建节点cur1,cur2分别遍历两个链表,newHead为合并后链表的头部,newTail为合并后链表的尾部,
如果L1的值小于L2则将L1元素添加至新链表,并且newTail向后移动,同理,直到最后有一方结束,则将未结束的指直接合并至新链表结尾,因为合并的是有序链表,若一开始有一方链表为空,直接返回不为空的即可。
public ListNode mergeTwoList(ListNode L1,ListNode L2){
ListNode cur1 = L1;
ListNode cur2 = L2;
ListNode newHead = null;
ListNode newTail = null;
if(L1 == null){
return L2;
}
if(L2 == null){
return L1;
}
while(cur1!=null && cur2!=null){
if(cur1.val<cur2.val){
if(newHead == null){
newHead = cur1;
newTail = cur1;
cur1 = cur1.next;
} else {
newTail.next=cur1;
newTail=newTail.next;
cur1=cur1.next;
}
} else {
if(newHead == null){
newHead = cur2;
newTail = cur2;
cur2 = cur2.next;
} else {
newTail.next=cur2;
newTail=newTail.next;
cur2=cur2.next;
}
}
if(cur1 == null){
newTail.next=cur2;
} else {
newTail.next=cur1;
}
}
return newHead;
}