前言:上一篇文章,我们具体讲述了链表的相关知识。本篇紧承上集,通过 9 道单链表较为 ”简单“ 的题目的讲解,让你领略单链表的别样的逻辑结构 “魅力“。同时,单链表作为笔试常考话题之一,简单题目的回顾希望能够帮助大家夯实操作单链表的基础,话不多说我们正式开始。
tip: 由于题目都较为基础,所以尽管没有附上图解,但配合注释大家应该能够明晰
重点:
1)思路:
(1)三指针
(2)头插
2)解法:
public ListNode ReverseList(ListNode head) {
if(head == null || head.next == null){
return head;
}
//三指针
ListNode preCur = null;
ListNode cur = head;
ListNode nextCur = null;
while(cur != null){
//保下引用
nextCur = cur.next;
//赋上引用
cur.next = preCur;
preCur = cur;
cur = nextCur;
}
return preCur;
}
public ListNode ReverseList(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode nextCur = null;
ListNode cur = head.next;
head.next = null;
while(cur != null){
nextCur = cur.next;
//使用 head 进行头插
cur.next = head;
head = cur;
cur = nextCur;
}
return head;
}
1)思路:
(1)快慢指针
2)解法:
public ListNode middleNode(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
1)思路:
2)解法:
public boolean isPalindrome(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;
}
//cur 到中间节点的后一个节点
ListNode cur = slow.next;
ListNode curNext = null;
//开始反转
while(cur != null){
curNext = cur.next;
cur.next = slow;
slow = cur;
cur = curNext;
}
//cur 从同头开始走,slow从尾开始走
cur = head;
while(cur != slow){
if(cur.val != slow.val){
return false;
//判断为偶数的情况
}else if(cur.next == slow){
break;
}
cur = cur.next;
slow = slow.next;
}
return true;
}
1)思路:
创建虚拟头结点 dummy,因为涉及链表的修改,可以省去很多特殊情况的判断
从头节点开始,外循环遍历链表,找到重复的节点后,内循环 跳过可能出现的连续重复节点
2)解法:
public ListNode deleteDuplicates (ListNode head) {
if(head == null || head.next == null) return head;
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode pre = dummy;
ListNode cur = head;
//2 进行删除
while(cur != null && cur.next != null){
// 找到相同的
if(cur.val == cur.next.val){
//注意要判断下一个节点是否为空,本节点为空进入外循环就已经判断了
while(cur.next != null && cur.val == cur.next.val){
cur = cur.next;
}
cur = cur.next;
pre.next = cur;
}else{
pre = cur;
cur = cur.next;
}
}
//4 返回
return dummy.next;
}
1 ) 思路:
(1)双指针
2 ) 解法:
public ListNode FindKthToTail (ListNode pHead, int k) {
// write code here
//快慢指针
//1 快指针先走 k - 1
if(pHead == null || k == 0) return null;
ListNode fast = pHead;
ListNode slow = pHead;
while(k > 1){
fast = fast.next;
if(fast == null){
return null;
}
k--;
}
while(fast.next != null){
fast = fast.next;
slow = slow.next;
}
return slow;
}
1 ) 思路:
( 1 ) 双指针
( 2 ) 长度统计
2 ) 解法:
public ListNode removeNthFromEnd (ListNode head, int n) {
// write code here
//解法1: 双指针
//1 创建虚拟头节点
ListNode newHead = new ListNode(-1);
newHead.next = head;
//2 快指针先走 n 步
ListNode fast = newHead;
ListNode slow = newHead;
while(n > 0){
fast = fast.next;
n--;
}
//3 走快慢指针同时走, 慢指针走到n - 1节点
while(fast.next != null){
fast = fast.next;
slow = slow.next;
}
//4 删除节点
slow.next = slow.next.next;
return newHead.next;
}
public ListNode removeNthFromEnd (ListNode head, int n) {
//解法2: 长度统计
//1 创建虚拟头结点
ListNode newHead = new ListNode(-1);
newHead.next = head;
//2 统计长度(加上虚拟头结点), 计算倒数 n 节点下标 nIndex
ListNode cur = newHead;
int size = 0;
while(cur != null){
size++;
cur = cur.next;
}
int nIndex = size - n;
//3 前进nIndex - 1步, 到达删除节点的前一个节点
cur = newHead;
for(int i = 0; i < nIndex - 1; i++){
cur = cur.next;
}
//4 删除节点
cur.next = cur.next.next;
return newHead.next;
}
1)思路:
2)解法:
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode newHead = new ListNode(-1);
ListNode cur1 = list1;
ListNode cur2 = list2;
ListNode cur = newHead;
//比较 cur1.val 和 cur2.val,连接到新链表
while (cur1 != null && cur2 != null) {
if (cur1.val < cur2.val) {
cur.next = cur1;
cur = cur.next;
cur1 = cur1.next;
} else {
cur.next = cur2;
cur = cur.next;
cur2 = cur2.next;
}
}
//非空的 cur1 / cur2 直接尾插到新链表
if (cur1 != null) {
cur.next = cur1;
}
if (cur2 != null) {
cur.next = cur2;
}
return newHead.next;
}
1)思路:
2)解法:
public ListNode partition(ListNode pHead, int x) {
// write code here
ListNode s1 = null;
ListNode e1 = null;
ListNode s2 = null;
ListNode e2 = null;
ListNode cur = pHead;
//以 x 为基点将元素放到 s1 s2 两链表中
while(cur != null){
if(cur.val < x){
//判断是否是第一次插入
if(s1 == null){
s1 = cur;
e1 = cur;
}else{
e1.next = cur;
e1 = cur;
}
}else{
if(s2 == null){
s2 = cur;
e2 = cur;
}else{
e2.next = cur;
e2 = cur;
}
}
cur = cur.next;
}
//判断 s1 是否为空,为空直接将 s2 赋值给 s1
if(s1 == null){
s1 = s2;
//不为空,连接两个链表
}else{
e1.next = s2;
}
//判断 e2 是否为空,不为空后驱直接设置为空,防止出现死循环
if(e2 != null){
e2.next =null;
}
return s1;
}
1)思路:
2)解法:
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null){
return null;
}
int lenA = 0;
int lenB = 0;
ListNode pl = headA;
ListNode ps = headB;
while(pl != null){
lenA++;
pl = pl.next;
}
while(ps != null){
lenB++;
ps = ps.next;
}
pl = headA;
ps = headB;
//找到较长链表 pl,向前走差值步
int forward = lenA - lenB;
if(forward < 0){
pl = headB;
ps = headA;
forward = - forward;
}
while(forward != 0){
pl = pl.next;
forward--;
}
//pl 和 ps 同一起跑线向前找交点
while(pl != ps){
pl = pl.next;
ps = ps.next;
}
return pl;
}
至此,文章就结束了,如果对各位小伙伴有所裨益的话,求 点赞、收藏、评论 三连,如有问题也欢迎各位看官朋友指正
下一篇博主会更新牛客 TOP101 中关于链表的题目,点个关注不迷路哦~