和链表相关的一些问题
和链表相关的一些问题
作者:Grey
原文地址:
在链表中删除指定值的所有节点
题目链接:LeetCode 203. Remove Linked List Elements
主要思路就是遍历链表,找到对应值的元素,就做删除操作,对于普遍位置来说,删除操作可以按如下方式进行
不过,需要注意一个边界条件,就是:如果要删除的节点就是头节点,那么经过删除后,会面临要换头的情况。
所以在一开始的时候,需要做如下判断
while (head != null && head.val == val) {
head = head.next;
}
即找到第一个不需要删的节点。,这个节点就是最后要返回的链表的头节点。
完整代码见
class Solution {
public static ListNode removeElements(ListNode head, int val) {
while (head != null && head.val == val) {
head = head.next;
}
if (head == null) {
// 所有节点都删除光了
return null;
}
ListNode newHead = head;
ListNode cur = head.next;
ListNode pre = head;
while (cur != null) {
if (cur.val == val) {
pre.next = cur.next;
} else {
pre = cur;
}
cur = cur.next;
}
return newHead;
}
}
两个链表相加问题
题目链接见:LeetCode 2. Add Two Numbers
没有特别的算法,就是要注意每次相加可能会有进位的问题,还有一个边界条件,由于是从左往右依次相加,所以最右侧如果相加后超过了 9 ,那么需要在最右侧的右侧继续进一位。例如:
.....8
+
.....7
=
.....51 <--注意得到5以后,还要继续向右侧进1。
完整代码见:
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if (l1 == null || l2 == null) {
return l1 == null?l2:l1;
}
ListNode newHead = new ListNode((l1.val + l2.val)%10);
ListNode cur = newHead;
// 进位
int carry = (l1.val + l2.val)>=10?1:0;
l1 = l1.next;
l2 = l2.next;
while (l1 != null && l2 != null) {
ListNode next = new ListNode((l1.val + l2.val + carry)%10);
carry = (l1.val + l2.val + carry)>=10?1:0;
cur.next = next;
cur = next;
l1 = l1.next;
l2 = l2.next;
}
while (l1 != null) {
ListNode next = new ListNode((l1.val + carry)%10);
carry = (l1.val + carry)>=10?1:0;
cur.next = next;
cur = next;
l1 = l1.next;
}
while (l2 != null) {
ListNode next = new ListNode((l2.val + carry)%10);
carry = (l2.val + carry)>=10?1:0;
cur.next = next;
cur = next;
l2 = l2.next;
}
if (carry != 0) {
cur.next = new ListNode(carry);
cur = cur.next;
}
return newHead;
}
}
求链表中点位置问题
题目描述见:LeetCode 876. Middle of the Linked List
本题主要解决的问题是:
如果一个链表中的节点个数是奇数,则返回中点;如果个数是偶数,则返回下中点。
通常这类问题都是使用快慢指针来做,思路如下
设置一个快指针fast
,一个慢指针slow
, 快指针一次走两步,慢指针一次走一步,快指针走到结尾的时候,慢指针正好到中点位置。
完整代码见:
public ListNode middleNode(ListNode h) {
if (null == h || h.next == null) {
return h;
}
ListNode slow = h;
ListNode fast = h;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
快慢指针还可以解决如下类似的问题,只不过是初始化快慢指针的节点有所不同而已。
-
输入链表头节点,奇数长度返回中点,偶数长度返回上中点;
-
输入链表头节点,奇数长度返回中点,偶数长度返回下中点;
-
输入链表头节点,奇数长度返回中点前一个,偶数长度返回上中点前一个;
-
输入链表头节点,奇数长度返回中点前一个,偶数长度返回下中点前一个。
解决上述问题,建议用举例子的方式来确定快慢指针的移动。
判断链表是否为回文结构
题目链接为:LeetCode 234. Palindrome Linked List
本题比较好理解的一种解法是使用栈的方式,先将节点全部入栈,然后依次弹出并和原链表一一对比。空间复杂度是O(N)
。
// 利用栈O(n)
public static boolean isPalindrome(ListNode head) {
Stack<ListNode> stack = new Stack<>();
ListNode c = head;
while (c != null) {
stack.push(c);
c = c.next;
}
c = head;
while (c != null) {
if (c.val != stack.pop().val) {
return false;
}
c = c.next;
}
return true;
}
本题也可以使用链表操作,将空间复杂度优化为O(1)
。
同时本题也需要使用快慢指针找到链表的中间位置,然后中间位置拆分左右两侧的链表来进行比较。整体流程如下图
完整代码见:
class Solution {
// 修改原链表,空间O(1)
public static boolean isPalindrome(ListNode head) {
// 0个节点
// 1个节点 都是回文
if (head == null || head.next == null) {
return true;
}
// 判断两个节点
if (head.next.next == null) {
return head.val == head.next.val;
}
// 判断三个节点
if (head.next.next.next == null) {
return head.val == head.next.next.val;
}
//到这一步,至少有四个节点
// 使用快慢指针
// 奇数来到中点前一个位置(假设为a)和中点后一个位置(假设为b)
// 偶数来到上中点位置(假设为a)和下中点位置(假设为b)
// head ... a 这个链表,链表反转一下 a...head
// 设置两个指针,一个指向a,一个指向b,每个位置对比,结果记录在result中
// 恢复整个链表
ListNode slow = head;
ListNode fast = head.next.next;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
ListNode a = slow;
ListNode b;
ListNode mid = null;
if (fast != null) {
// 链表个数为奇数
mid = a.next;
b = a.next.next;
} else {
b = a.next;
// 链表个数为偶数
}
// 断开链表
a.next = null;
// 反转前半部分链表
ListNode c = reverse(head);
boolean result = true;
ListNode leftStart = c;
ListNode rightStart = b;
while (leftStart.next != null) {
if (leftStart.val != rightStart.val) {
result = false;
}
leftStart = leftStart.next;
rightStart = rightStart.next;
}
if (leftStart.val != rightStart.val) {
result = false;
}
// leftStart来到开始节点
// rightStart来到末尾节点
ListNode cur = reverse(leftStart);
while (cur.next != null) {
cur = cur.next;
}
if (mid == null) {
cur.next = b;
} else {
cur.next = mid;
mid.next = b;
}
return result;
}
private static ListNode reverse(ListNode head) {
ListNode pre = null;
ListNode cur = head;
while (cur != null) {
ListNode tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
}
更多
本文中所有图例见:processon
参考资料
本文来自博客园,作者:Grey Zeng,转载请注明原文链接:https://www.cnblogs.com/greyzeng/p/16629407.html