目录
面试题02.04.分割链表,将小于x的放x前面,大于的放后面
83.删除升序链表中重复的元素,使每个元素只出现一次
第一个正方形的节点即为我们自己定义的虚拟头节点dummyHead,使cur从头节点出发一直向后移动,prev和cur一起移动,当遇到重复元素时,让prev指向第一个不重复元素
public class LeetCode83 {//存在一个按升序排列的链表,给你这个链表的头节点 head ,
// 请你删除所有重复的元素,使每个元素 只出现一次 。
public ListNode deleteDuplicates(ListNode head) {
ListNode dummyHead=new ListNode(101);
dummyHead.next=head;
ListNode prev=dummyHead;
ListNode cur=prev.next;
while (cur!=null){
if(cur.val==prev.val){
prev.next=cur.next;
}else {
prev=prev.next;//prev和cur都不是重复元素
} cur=cur.next;//cur一直向后走
}return dummyHead.next;
}
}
82.删除链表中所有存在数字重复情况的节点
方法一:
使用三个索引:prev、cur、next
public ListNode deleteDuplicates(ListNode head) {
ListNode dummyHead = new ListNode(101);
dummyHead.next = head;
ListNode prev = dummyHead;
ListNode cur = prev.next;
while(cur != null){
ListNode next = cur.next;
if(next == null){
return dummyHead.next;
}else{
//当前链表至少有两个节点
if(cur.val != next.val){
//三引用同时向后移动
prev = prev.next;
cur = cur.next;
next = next.next;
}else{
while(next != null && cur.val == next.val){
next = next.next;
}
//prev指向重复节点前驱,next指向重复节点后继
prev.next = next;
//更新cur的指向
cur = next;
}
}
}
return dummyHead.next;
}
方法二:
if (head == null) {
return head;
}
ListNode dummyHead = new ListNode(101);
dummyHead.next = head;
ListNode prev = dummyHead;
ListNode next = prev.next;
while (next != null) {
//找到重复的开始
while (next.next != null && next.val != next.next.val) {
prev = prev.next;
next = next.next;
}
//找到重复的范围
while (next.next != null && next.val == next.next.val) {
next = next.next;
}
//走到这里结果一共有三种:
//1. next.next != null 并且限定了一段重复范围,此时进行去重
//2. last.next == null && 限定了一段重复范围,此时进行去重,使prev.next = null
//3. last.next == null && prev.next == next,这说明就不用进行去重
if (prev.next != next) {
//说明中间有重复节点
//prev永远指向的是重复节点的前驱
//next.next为重复节点的后继
prev.next = next.next;
}
//为了保证恢复的和最开始一致
next = next.next;
}
return dummyHead.next;
}
}
剑指offer22.找链表中倒数第k个节点
定义一个fast和low指向头节点,fast先从头出发走k步,之和fast和low一起同步向后移,fast和low一直相隔k个单位,当fast为空时,low即为倒数第k个节点
public class LeetCodeOffer22 {//找链表中倒数第k个节点
public ListNode getKthFromEnd(ListNode head, int k) {
ListNode fast=head;
ListNode low=head;
for (int i = 0; i < k; i++) {
fast=fast.next;
}
while (fast!=null){
fast=fast.next;
low=low.next;
}return low;
}
}
876. 找链表的中间结点,若有两个中间节点,则返回第二个
使用快慢指针,快指针一次走两步,慢指针一次走一步,当快指针为空或者它的下一个节点为空时,慢指针指向的就是中间节点
public class LeetCode876 {
public ListNode middleNode(ListNode head) {
ListNode fast=head;
ListNode low=head;
while (fast!=null&&fast.next!=null){
fast=fast.next.next;
low=low.next;
}return low;
}
}
206.将链表反向输出
1.使用头插法创建出一个新的链表,不要求空间复杂度时使用
public class LeetCode206 {
public ListNode reverseList(ListNode head) {
if(head==null||head.next==null) {
return head;
}else {
ListNode dummyHead=new ListNode(5001);
while (head!=null){
ListNode node=new ListNode(head.val);
node.next=dummyHead.next;
dummyHead.next=node;
head=head.next;
}return dummyHead.next;
}}
2.原地移动,在原来的链表上操作
public ListNode reverseList(ListNode head) {
if(head==null||head.next==null){
return head;
}
else {
ListNode prev=null;
ListNode cur=head;
while (cur!=null){
ListNode next=cur.next;
cur.next=prev;
prev=cur;
cur=next;
}return prev;
}
}
3.递归
public ListNode reverseList(ListNode head) {
if (head==null||head.next==null){
return head;
}else {
ListNode sec = head.next;
ListNode newHead = reverseList(head.next);
sec.next = head;
head.next = null;
return newHead;
}
}
234.判断该链表是否为回文链表
如1-->2-->2-->1反过来依然是1-->2-->2-->1
先找到中间节点,将中间节点以后的链表反向输出(使用上一题的方法回文),将新链表和前半段链表相比较即可。
也可以将整个链表回文,这里就不再赘述了
public class LeetCode234 {
public boolean isPalindrome(ListNode head) {
ListNode middle=middleNode(head);
ListNode l2=reverseList(middle);
while (l2!=null){
if(l2.val!=head.val) {
return false;
}l2=l2.next;
head=head.next;
}return true;
} public ListNode middleNode(ListNode head) {//中间节点
ListNode fast=head;
ListNode low=head;
while (fast!=null&&fast.next!=null){
fast=fast.next.next;
low=low.next;
}return low;
}
public ListNode reverseList(ListNode head) {//使用递归将链表反序输出(第206题)
if (head==null||head.next==null){
return head;
}else {
ListNode sec = head.next;
ListNode newHead = reverseList(head.next);
sec.next = head;
head.next = null;
return newHead;
}
}}
21.合并两个有序链表
创建一个虚拟头节点,last指向它。从头节点开始比较,值小的链表接在虚拟头的后面,再用该链表的下一个值和另外一个链表的头节点比较,以此类推
public class LeetCode21 {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if (list1==null){
return list2;
}
if (list2==null){
return list1;}
ListNode dummyHead=new ListNode(101);
ListNode last=dummyHead;
while (list1!=null && list2!=null){
if(list1.val<= list2.val){
last.next=list1;
last=list1;
list1=list1.next;
}else {
last.next=list2;
last=list2;
list2=list2.next;
}}
if(list1==null){//此时l1或者l2为空
last.next=list2;
}else {
last.next=list1;
}return dummyHead.next;
}
}
141.判断是否为环形链表
使用快慢指针,快慢指针相遇即为环形链表
public class LeetCode141 {
public boolean hasCycle(ListNode head) {
ListNode fast=head;
ListNode low=head;
while (fast!=null&&fast.next!=null){
fast=fast.next.next;
low=low.next;
if (fast==low){
return true;
}
}return false;
}
}
142.找环形链表的入环节点
使用快慢指针,快慢指fast和low从头开始走,一个一次走两步,慢的一次走一步,根据上述141号题,若带环二者必会相遇,设在b点相遇,此时,
fast走的长度:a+n(b+c)
low走的长度:a+b
根据fast走的是low的二倍 可推出公式:a=(n-1)(a+b)+c
此时low在b点,使third从头开始和low同时开始以相同速度移动,根据推出的公式,二者在环的入口相遇
public class LeetCode142 {
public ListNode detectCycle(ListNode head) {
ListNode fast=head;
ListNode low=head;
while (fast!=null && fast.next!=null){
fast=fast.next.next;
low=low.next;
if(low==fast){
ListNode third=head;
while (third!=low){
third=third.next;
low=low.next;
}return low;
}
}return null;
}
}
160.相交链表,找相交的节点
涉及相交部分长度是c,让A、B同时开始遍历,有一方到达终点,让其从对方的表头出发继续遍历,A走的路线:a+c+b, B走的路线:b+c+a,二者会在交点处相遇
public class LeetCode160 {//相交链表
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode pA=headA;
ListNode pB=headB;
while (pA!=pB){
pA=pA==null ? headB:pA.next;
pB=pB==null ? headA:pB.next;
}return pA;
}
}
面试题02.04.分割链表,将小于x的放x前面,大于的放后面
public class LeetCodeOffer0204 {//分割链表,将小于x的放x前面,大于的放后面
public ListNode partition(ListNode head, int x) {
if(head==null){
return null;
}
ListNode smallHead=new ListNode(101);
ListNode smallTail=smallHead;
ListNode bigHead=new ListNode(101);
ListNode bigTail=bigHead;
while (head!=null){//遍历原链表
if (head.val<x){
smallTail.next=head;
smallTail=head;//尾插入小链表
}else {
bigTail.next=head;
bigTail=head;
}
head=head.next;
}
bigTail.next=null;//拼接两个链表
bigTail.next=bigHead.next;
return smallHead.next;
}
}
链表有关的题就更新这么多啦,注意!!一定得多画图理解 !!
或许有描述不到位的或者代码有什么问题欢迎多多评论