1.反转单链表
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表
如
得到如下链表
代码实现:
public ListNode reverseList(ListNode head) {
if(head == null){
return null;
}
ListNode cur = head;
ListNode curNext;
ListNode prev = null;
while(cur != null){
curNext = cur.next;
cur.next = prev;
prev = cur;
cur = curNext;
}
return prev;
}
2.返回链表中间节点
给定一个头结点为 head
的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
对于该题,可用快慢指针来解决:
定义一个fast,再定义一个slow,让fast一次走两步,slow一次走一步,当fast = null 时,此时,slow对应的节点就是该链表的中间节点。
奇数个节点
偶数个节点
代码实现:
public ListNode middleNode(ListNode head) {
if(head == null){
return null;
}
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
3.返回链表倒数第k个节点
方法一:一般做法
假设链表长度为len,则倒数第k个节点,就为正着数第len-k个节点,就可以直接返回第len-k个节点。
方法二:双指针
对于方法一,大多数人都能想到,但对于面试官来说,显然方法一不够好不够快。而本题可以利用快慢指针来解决。
从倒数第一个到倒数第k个,中间差k-1步。定义fast,slow都等于head。先让fast走k-1步,然后fast与slow一起走,直至fast走到最后一个节点,此时slow对应节点就是所求节点。
代码实现:
public ListNode FindKthToTail(ListNode head,int k) {
if(k <= 0 || head == null){
return null;
}
ListNode fast = head;
ListNode slow = head;
for(int i = 0;i <= k-1;i++){
fast = fast.next;
if(fast == null){
return null;
}
}
while(fast != null){
slow = slow.next;
fast = fast.next;
}
return slow;
}
4.合并有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
假定链表为都为升序链表,该题涉及两个链表,可以利用一个傀儡节点来解决问题。
傀儡节点:
ListNode newhead = new ListNode(-1);
ListNode tmp = newhead;即val域为-1,next域为tmp
分析:先对两个节点值进行判断,若headA.val <= headB.val,则令tmp.next = headA,使傀儡节点与headA串联起来,然后让headA向后走一步(为后续的headA与headB的大小进行判断),再让tmp向后走一步。若此时headA.val > headB.val,则tmp.next = headB,使得链表串起来,再让headB向后走一步,然后使tmp向后走一步。直至headA = null或headB = null。
代码实现:
public ListNode mergeTwoLists(ListNode headA, ListNode headB) {
ListNode newhead = new ListNode(-1);
ListNode tmp = newhead;
while(headA != null && headB != null){
if(headA.val <= headB.val){
tmp.next = headA;
headA = headA.next;
tmp = tmp.next;
}else{
tmp.next = headB;
headB = headB.next;
tmp = tmp.next;
}
}
if(headA != null){
tmp.next = headA;
}
if(headB != null){
tmp.next = headB;
}
return newhead.next;
}
5.将值为x的节点插入链表,使小于x的节点排在x之前
现有一链表的头指针 ListNode head,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针
分析:本题可以将链表分开成两个,一边是小于x的,一边是大于x的,用cur遍历一遍数组 即可得到结果。小于x的部分,定义一个BeforStar,BeforEnd,大于x的部分AfterStar,AfterEnd,即bs,be,as,ae。若是第一次实例化小于x的部分,让bs,be同时指向cur,若是第一次实例化大于x的部分,让as,ae同时指向cur。若不是第一次,利用尾插法即可。
注意:1.小于x的部分可能为空 2.大于x的部分可能最一个节点的next域不是null
代码实现:
public ListNode partition(ListNode head, int x) {
ListNode cur = head;
ListNode bs = null;
ListNode be = null;
ListNode as = null;
ListNode ae = null;
while(cur != null){
if(cur.val < x){
if(bs == null){
bs = cur;
be = cur;
}else{
be.next = cur;
be = be.next;
}
}else{
if(as == null){
as = cur;
ae = cur;
}
else{
ae.next = cur;
ae = ae.next;
}
}
cur = cur.next;
}
if(bs == null){
return as;
}
be.next = as;
if(as != null){
ae.next = null;
}
return bs;
}
6.删除链表中重复的的节点
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表 1->2->3->3->4->4->5 处理后为 1->2->5
分析:该题可以利用傀儡节点,分析对于cur.val != cur.next.val,即cur.val唯一(不重复),将该节点置于傀儡节点之后即可
注意:最后一个节点一定为null.
public ListNode deleteDuplication(ListNode head) {
ListNode cur = head;
ListNode newHead = new ListNode(-1);
ListNode tmp = newHead;
while(cur != null){
if(cur.next != null && cur.val == cur.next.val){
while(cur.next != null && cur.val == cur.next.val){
cur = cur.next;
}
cur = cur.next;
}else{
tmp.next = cur;
tmp = tmp.next;
cur = cur.next;
}
}
tmp.next = null;
return newHead.next;
}