链表作为数据结构的重要知识点,通常作为大厂们笔试面试题,这里我写了两篇博客来解决,一共10道题,此篇为后五道题。
上篇博客: 前五道题
目录
1. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。
5.给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NU
1. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。
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;
}
要用x分割链表,首先我们要定义5个节点,cur用来便利原来链表,剩下的我们把分割的先划分为两部分,小于x的在前,用bs做头be便利,大于x的放在后面,as做头ae便利。接着就进入循环进行便利,对cur的val值与x比较,小的接在be后,大的接在ae后,最后将两部分相连就成。注意,判断大小时,还要判断是否为第一次,如果为第一次bs,be都应为cur。最后在将ae.next也就是最后一个节点的next值设为null。
2.链表的回文结构。
public boolean chkPalindrome(ListNode head) {
if (head == null || head.next == null) {
return true;
}
//1、找到链表的中间节点
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
//2、翻转
ListNode cur = slow;
ListNode curNext = cur.next;
while (curNext != null) {
slow = curNext;
curNext = curNext.next;
slow.next = cur;
cur = slow;
}
//3、开始一个从头走,一个从尾巴走,直到相遇
while (head != slow) {
if (head.val != slow.val) {
return false;
}
if (head.next == slow) {
return true;
}
head = head.next;
slow = slow.next;
}
return true;
}
要判断链表是否回文我们分三步,第一,找到最中间节点,第二,从中间节点开始翻转,第三,一个从头走,一个从尾巴走,比较每个值是否相同,找中间值我们定义快慢节点即可,翻转刚才也讲到,最后直接比较即可。
3.输入两个链表,找出它们的第一个公共结点。
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null) {
return null;
}
ListNode pl = headA;//指向长的链表
ListNode ps = headB;//指向短的链表
//1、分别求长度
int lenA = 0;
int lenB = 0;
while (pl != null) {
lenA++;
pl = pl.next;
}
while (ps != null) {
lenB++;
ps = ps.next;
}
//需要重新修改指向
pl = headA;
ps = headB;
//2、已经知道两个链表的长度了
int len = lenA-lenB;
if(len < 0) {
pl = headB;
ps = headA;
len = lenB - lenA;
}
//1、求长度 2、pl永远指向 最长的那个链表 ps永远指向最短的那个链表
//3、就是让最长的链表走len步
while(len>0){
pl=pl.next;
len--;
}
//4、一人一步走 直到相遇
while(pl!=ps){
pl=pl.next;
ps=ps.next;
}
//5、是不是两个都是null-》没有相交
if(pl==null){
return null;
}
return pl;
}
求两个链表的交点,首先设一个pl和ps节点,pl指向长的,ps指向短的。接着我们分别求两个链表的长度,分别为lenA和lenB,如果两个链表相交,则长的减短的就为长的多余的部分,因此,我们设len为lenA,lenB的差值,接着判断如果len小于0,则是B链表长,我们要修改pl和ps的指向,到这里,ps永远指向短的,pl永远指向长的,多了len个节点,所以,长的,先走len步,接着两者同时走,知道他们相遇,就为他们的交点。注意,最后我们要对他们判断,如果都为null则说明不想交,返回null。
4.给定一个链表,判断链表中是否有环。
思路:
快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表其实位置开始运行,如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾。比如:陪女朋友到操作跑步减肥。
public boolean hasCycle(ListNode head) {
if (head == null) {
return false;
}
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
break;
}
}
if (fast == null || fast.next == null) {
return false;
} else {
return true;
}
}
还是定义两个快慢指针,fast走两步,slow走一步,如果相遇就跳出循环,接着进行判断,如果fast或者fast。next为空,则说明他不是环否则为环。
5.给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NUL
public ListNode detectCycle(ListNode head) {
if (head == null || head.next == null) {
return null;
}
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
break;
}
}
if (fast != null && fast.next != null) {
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
} else {
return null;
}
我们至于要在上题判断完成环后再让一个节点回到head从头开始走,直到相遇就为入环点。