Loading

和链表相关的一些问题

和链表相关的一些问题

作者:Grey

原文地址:

博客园:和链表相关的一些问题

CSDN:和链表相关的一些问题

在链表中删除指定值的所有节点

题目链接:LeetCode 203. Remove Linked List Elements

主要思路就是遍历链表,找到对应值的元素,就做删除操作,对于普遍位置来说,删除操作可以按如下方式进行

image

image

image

不过,需要注意一个边界条件,就是:如果要删除的节点就是头节点,那么经过删除后,会面临要换头的情况。

所以在一开始的时候,需要做如下判断

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;
  }

快慢指针还可以解决如下类似的问题,只不过是初始化快慢指针的节点有所不同而已。

  1. 输入链表头节点,奇数长度返回中点,偶数长度返回上中点;

  2. 输入链表头节点,奇数长度返回中点,偶数长度返回下中点;

  3. 输入链表头节点,奇数长度返回中点前一个,偶数长度返回上中点前一个;

  4. 输入链表头节点,奇数长度返回中点前一个,偶数长度返回下中点前一个。

解决上述问题,建议用举例子的方式来确定快慢指针的移动。

判断链表是否为回文结构

题目链接为: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)

同时本题也需要使用快慢指针找到链表的中间位置,然后中间位置拆分左右两侧的链表来进行比较。整体流程如下图

image

image

image

image

image

完整代码见:

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

算法和数据结构学习笔记

算法和数据结构学习代码

参考资料

算法和数据结构体系班-左程云

posted @ 2022-08-26 22:07  Grey Zeng  阅读(401)  评论(0编辑  收藏  举报