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

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

你可能感兴趣的:(LeetCode刷题之链表)