LeetCode刷题之链表

链表(Linked List)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。

由于不必须按顺序存储,链表在插入的时候可以达到 O(1)的复杂度,比另一种线性表 —— 顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要 O(n)的时间,而顺序表相应的时间复杂度分别是 O(log/ n)和O(1)。

链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。

各题通用节点类:
    public class ListNode {
        int val;
        ListNode next;

        ListNode(int x) {
            val = x;
        }
    }

237. 删除链表中的节点

请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点。传入函数的唯一参数为 要被删除的节点 。

示例 1:

输入:head = [4,5,1,9], node = 5
输出:[4,1,9]
解释:给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.

题解:
class Solution {
    /**
     * 思路:
     * 杀不掉自己,就杀掉下一个
     * 当前节点不删除,将node后一个节点的值保存在该node中,将该node的next指向下下一个,删除下一个节点
     * @param node
     */
    public void deleteNode(ListNode node) {
        node.val = node.next.val;
        node.next = node.next.next;
    }
}

1290. 二进制链表转整数

给你一个单链表的引用结点 head。链表中每个结点的值不是 0 就是 1。已知此链表是一个整数数字的二进制表示形式。

请你返回该链表所表示数字的 十进制值 。

示例 1:

输入:head = [1,0,1]
输出:5
解释:二进制数 (101) 转化为十进制数 (5)

题解:
class Solution {
     /**
     * 思路:
     * 遍历链表,将链表的值存入栈中,遍历栈,依次弹出栈,每个数字✖️2的pos次方,达到链表反转的功能
     * 然后按照该栈的顺序将二进制转十进制
     * @param head
     * @return
     */
    public int getDecimalValue(ListNode head) {
        Stack stack = new Stack<>();
        stack.push(head.val);
        //链表值存入栈
        while (head.next != null) {
            stack.push(head.next.val);
            head = head.next;
        }
        int pos = 0;
        int total = 0;
        while (!stack.isEmpty()) {
            //每个数字在对应pos位置乘以2的pos次方
            total += (stack.pop() << pos);
            pos++;
        }
        return total;
    }
}

剑指 Offer 22. 链表中倒数第k个节点

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。

示例:

给定一个链表: 1->2->3->4->5, 和 k = 2.
返回链表 4->5.

题解:
class Solution {

     /**
     * 思路:
     * 双指针法:用former指针指向head,用latter指针指向第k个节点,使former和latter间隔k个位置。
     * 循环往后走,former指针和latter指针都依次往后移,当latter指针的next为空时,later指向最后一个,
     * 那么此时former正好指向的是倒数第k个位置。
     * @param head
     * @param k
     * @return
     */
    public ListNode getKthFromEnd(ListNode head, int k) {
        ListNode former = head;
        ListNode latter = head;
        //将latter指向第k个节点
        for (int i=0;i

剑指 Offer 06. 从尾到头打印链表

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

示例 1:

输入:head = [1,3,2]
输出:[2,3,1]

题解:
class Solution {
     /**
     * 思路:
     * 遍历链表存到栈中,遍历栈弹出栈中元素,保存到数组中
     * @param head
     * @return
     */
    public int[] reversePrint(ListNode head) {

        Stack stack = new Stack<>();
        ListNode temp = head;
        while (temp != null) {
            stack.push(temp);
            temp = temp.next;
        }
        int size = stack.size();
        int[] array = new int[size];
        for (int i = 0; i < size; i++) {
            array[i] = stack.pop().val;
        }
        return array;
    }
}

206. 反转链表

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

题解:
class Solution {
     /**
     * 思路: 双指针迭代
     * 我们可以申请两个指针,第一个指针叫 pre,最初是指向 null 的。
     * 第二个指针 cur 指向 head,然后不断遍历 cur。
     * 每次迭代到 cur,都将 cur 的 next 指向 pre,然后 pre 和 cur 前进一位。
     * 都迭代完了(cur最后一次会被置为null),pre 就是最后一个节点了。
     * @param head
     * @return
     */
    public ListNode reverseList(ListNode head) {
        ListNode preNode = null;
        ListNode curNode = head;
        while (curNode != null) {
            //注意:此处的curNode.next只需要暂存起来,因为后面curNode.next会改变
            ListNode temp = curNode.next;
            curNode.next = preNode;
            //preNode/curNode节点往后移动
            preNode = curNode;
            curNode = temp;
        }
        return preNode;
    }
}

反转链表 II

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

题解:
class Solution {

    /**
     * 根据上图思路:
     * 1.需要快进到反转区间左位置
     * 2.使用变量记住区间前一个位置和第一个位置节点
     * 3.使用经典四步反转left到right区间的节点
     * 4.将反转后的链表与原链表进行拼接
     */
    public ListNode reverseBetween(ListNode head, int left, int right) {

        ListNode pre = null, cur = head;
        //cur在pre的前一个位置
        for (int i=0;i

21. 合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例:

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

题解:
class Solution {
    /**
     * 思路:
     * 创建一个新头节点preNode,比较l1和l2,preNode指向小的节点
     * 然后将小的节点往后移动一个,将preNode往后移动一个,继续比较l1和l2
     * 直到l1或者l2某一个为null,那么一种一个合并完,然后将preNode指向另一个非空节点
     * @param l1
     * @param l2
     * @return
     */
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode preNode = new ListNode(-1);
        ListNode head = preNode;
        while (l1!=null && l2!=null) {
            if (l1.val <= l2.val) {
                //取l1的节点作为新节点的首节点
                preNode.next = l1;
                //往后移动节点
                l1 = l1.next;
            } else {
                //取l2的节点作为新节点的首节点
                preNode.next = l2;
                //往后移动节点
                l2 = l2.next;
            }
            //preNode往后移以用来保存新的节点
            preNode = preNode.next;
        }
        //当某个链表为空,非空链表剩下节点拼接在head链表的末尾
        preNode.next = l1==null?l2:l1;

        return head.next;
    }
}

相交链表

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

题解:
public class Solution {
    //创建两个指针 pApA 和 pBpB,分别初始化为链表 A 和 B 的头结点。然后让它们向后逐结点遍历。
    //当 pApA 到达链表的尾部时,将它重定位到链表 B 的头结点 (你没看错,就是链表 B); 类似的,当 pBpB 到达链表的尾部时,将它重定位到链表 A 的头结点。
    //若在某一时刻 pApA 和 pBpB 相遇,则 pApA/pBpB 为相交结点。
    //为什么这种方法是可行的,因为当A、B都走到公共节点的时候,正好走了自己的路,又走了对方的路,两个指针走的距离相等
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode n1 = headA;
        ListNode n2 = headB;
        while(n1 != n2) {
            if(n1 != null) {
                //有后面节点,继续往后移动
                n1 = n1.next;
            } else {
                n1 = headB;
            }

            if(n2 != null) {
                n2 = n2.next;
            } else {
                n2 = headA;
            }
        }

        //当n1==n2了,即各自走了一圈半到了第一个相交节点,返回n1或n2都可以
        return n1;
    }

}

回文链表

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

题解:
    public boolean isPalindrome(ListNode head) {
        //思路:采用双指针法:将链表的各个值存放到集合中,
        //启动start、end位置,前后对应对比数值看是否相等,再依次往中间靠,直到start、end相等
        ArrayList data = new ArrayList();
        while(head != null) {
            data.add(head.val);
            head = head.next;
        }
        int start = 0, end = data.size()-1;
        while(start < end) {
            if(data.get(start) == data.get(end)) {
                start++;
                end--;
            } else {
                return false;
            }
        }
        return true;
    }

版权声明:
作者:admin
链接:https://www.techfm.club/p/44689.html
来源:TechFM
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>