LeetCode刷题之路:链表(2)

奔涌的LeetCoder(二):链表(2)

这是阿茄的LeetCode学习之路系列推文“奔涌的LeetCoder”的第二节的第二讲,将介绍数据结构中链表相关问题的解法,本讲总共整理4题。

83.删除排序链表中的重复元素[简单]

说明:
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

示例:

输入: 1->1->2->3->3
输出: 1->2->3

解答:

解法一:迭代法,需考虑到连续多个(三个及三个以上节点相等的情况)

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head != null){
        //初始化指针pre,cur
        ListNode pre = head;
        ListNode cur = head.next;
        while(cur != null){
            ListNode temp = cur.next;
            if(pre.val == cur.val){
                cur = temp;       
            }
            else{   
                pre.next = cur;
                cur = temp;
                pre = pre.next;   
            }
        }
        pre.next = null; 
        return head;
        }
        //空链表,返回空链
        else{
            return head;
        }
    }
}

解法二:递归法,好好理解一下,递归比较玄幻,看递归算法需要学会从后往前推理。

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head == null || head.next == null) return head;//空链或者单节点链
        head.next = deleteDuplicates(head.next);
        return head.val == head.next.val ? head.next : head;
    }
}

注:递归算法在链表问题的解法上是很常用的,但是往往由于其不好理解,“拐弯抹角”,对初学者并不友好,“递龟”是门艺术,就跟人类的本质是复读一样。递龟不烧键盘次数,不烧鼠标耐久,就是烧脑。理解递归算法需要学会从后往前推到,将后面看作黑匣子,并结合图例思考,方便理解。

19. 删除链表的倒数第N个节点[中等]

说明:
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。进阶:扫描实现。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.

解答:

解法一:双指针移动法。front和later指针起始位置一样,利用front指针先动n步制造指针位置差距后双指针按同速度前进,当front指针指向链表末端时,later指针指向链表倒数第n个节点。时间复杂度O(L),L 为链表长度,空间复杂度O(1)。

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode pre = new ListNode(-1);
        pre.next = head;
        ListNode front = pre; 
        ListNode later = pre;
        while(n!=0){
            front = front.next;
            n--;
        } 
        while(front.next != null){
            front = front.next;
            later =later.next;
        }
        later.next = later.next.next;
        return pre.next;

    }
}

解法二:考虑先遍历链表求出链表长度,再移动L-n来定位要删除的节点,不过此方法时间复杂度要高,因为在再遍历链表一遍的基础上需要再重新遍历要删除的节点。具体代码不再展开。

24. 两两交换链表中的节点[中等]

说明:
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.

解答:

解法一:迭代法。创建哑节点做链表新头并指针pre指向哑节点,前进移动指针pre并创建新的指针pointer1和pointer2指向要互换的链表节点,进行swap操作,pre指针继续前进移动两步,开始下一轮迭代。以此类推。算法时间复杂度O(L),L为链表长度。空间复杂度为O(1)。

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode newhead = new ListNode(-1);
        ListNode pre = newhead;
        pre.next = head;
        while(pre.next != null && pre.next.next != null){
            ListNode pointer1 = pre.next;
            ListNode pointer2 = pre.next.next;
            pre.next = pointer2;
            pointer1.next = pointer2.next;
            pointer2.next = pointer1;
            pre = pre.next.next;
        }
        return newhead.next;
    }
}

在这里插入图片描述

解法二:递归法。空时复杂度均为O(L)。

class Solution {
    public ListNode swapPairs(ListNode head) {
        while(head == null || head.next == null){
            return head;
        }
        ListNode pointer1 = head;
        ListNode pointer2 = head.next;
        pointer1.next = swapPairs(pointer2.next);
        pointer2.next = pointer1;
        return pointer2;
    }
}

445. 两数相加II[中等]

说明:
给你两个非空链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。

示例:

输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 8 -> 0 -> 7
注:7243+564=7807

解答:

据说反转链表,逆序链表得想到栈!!!
解法一:考虑将两链表数据分别压入各自栈中,根据先进后出规则加减。时间复杂度为O(max(m,n)),m,n分别为链表长度。空间复杂度,由于需要栈空间,复杂度为O(m+n)。

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        Deque<Integer> stack1 = new LinkedList<Integer>();
        Deque<Integer> stack2 = new LinkedList<Integer>();
        //数据压入栈
        while(l1 != null){
            stack1.push(l1.val);
            l1 = l1.next;
        }
        while(l2 != null){
            stack2.push(l2.val);
            l2 = l2.next;
        }
        int flag = 0;//进位标识
        ListNode ansNode = null;
         while (!stack1.isEmpty() || !stack2.isEmpty() || flag != 0){
            int plus1 = stack1.isEmpty() ? 0 : stack1.pop();
            int plus2 = stack2.isEmpty() ? 0 : stack2.pop();
            int sum = plus1 + plus2 + flag;
            flag = sum / 10;
            sum = sum % 10;
            ListNode newNode = new ListNode(sum);
            newNode.next = ansNode;
            ansNode = newNode;
        }
        return ansNode;
    }
}

解法二:考虑先将两条链表反转,参考题号[206],然后完成求和操作。具体代码不再具体列出。

敲代码的阿茄
文章内容会在个人微信公众号同步更新,欢迎关注“敲代码的阿茄”!!!

猜你喜欢

转载自blog.csdn.net/Joel_wen/article/details/108803712
今日推荐