常见算法题目:链表(一)

115 阅读3分钟

前言

如果想进大厂工作,除了基础知识,项目经验,还有一些非常重要的能力需要锻炼,其中最重要的就是算法。算法题千千万,但是类型也就几十种,接下来的系列文章,我将面试中常见的算法题类型进行归纳。


链表面试题01. 移除重复节点

编写代码,移除未排序链表中的重复节点。保留最开始出现的节点

示例1:
输入:[1, 2, 3, 3, 2, 1]
输出:[1, 2, 3]

示例2:
输入:[1, 1, 1, 1, 2]
输出:[1, 2]


提示: 链表长度在[0, 20000]范围内
链表元素在[0, 20000]范围内

进阶:
如果不得使用临时缓冲区,该怎么解决?


代码

我们在给定的链表上使用两重循环,其中第一重循环从链表的头节点开始,枚举一个保留的节点,这是因为我们保留的是「最开始出现的节点」。第二重循环从枚举的保留节点开始,到链表的末尾结束,将所有与保留节点相同的节点全部移除。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeDuplicateNodes(ListNode head) {
        ListNode nodeA = head;
        if (nodeA == null) {
            return head;
        }

        while (nodeA != null) {
            ListNode nodeB = nodeA;
            while (nodeB.next != null) {
                if (nodeB.next.val == nodeA.val) {
                    nodeB.next = nodeB.next.next;
                } else {
                    nodeB = nodeB.next;
                }
            }

            nodeA = nodeA.next;
        }

        return head;
    }
}

链表面试题02. 返回倒数第 k 个节点

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。

示例:
输入: 1->2->3->4->5 和 k = 2
输出: 4

说明: 给定的 k 保证是有效的。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public int kthToLast(ListNode head, int k) {
        // 链表长度
        int count = 0;
        // 结果
        int result = 0;
        // 初始化一个链表临时节点
        ListNode temp = head;

        // 计算出链表长度
        while (temp.next != null) {
          temp = temp.next;
          count++; 
        }
        temp = head;

        for (int i = 0; i <= count - k; i++) {
            temp = temp.next;
        }

        return temp.val;
    }
}

链表面试题03. 删除中间节点

实现一种算法,删除单向链表中间的某个节点(即不是第一个或最后一个节点),假定你只能访问该节点。

示例: 输入:单向链表a->b->c->d->e->f中的节点c
结果:不返回任何数据,但该链表变为a->b->d->e->f


分析:
一道抖机灵的题
脑筋急转弯
将下一个节点值赋值给当前节点
将当前节点的next指针指向下下个节点


代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public void deleteNode(ListNode node) {
        // 链表4 → 8 → 9 → 2 → 7
        // 删除9 得到链表4 → 8 → 2 → 7
        // 如果知道该链表的头结点,可以遍历,找到该结点并且删除
        // 但是不知道这个结点的地址,并且还不知道该链表的头结点
        // 可以更换该这个结点的数据为下一个结点,然后删除下一个结点
        // 例如把9替换为2,链表4 → 8 → 2 → 2 → 7
        // 然后删除2,得到4 → 8 → 2 → 7

        // 将这个结点的数据替换为下一个结点
        node.val = node.next.val;
        // 删除下一个结点
        node.next = node.next.next;
    }
}

链表面试题04. 分割链表

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

你不需要 保留 每个分区中各节点的初始相对位置。

image

提示:
链表中节点的数目在范围 [0, 200] 内
-100 <= Node.val <= 100
-200 <= x <= 200


第一种解法:

思路:
初始化两个集合
遍历链表,将小于x的存入一个集合,将大于或者等于x的存入另外一个集合
将两个集合的数据存入一个新的链表,返回这个新链表的第一个元素

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode partition(ListNode head, int x) {
        ListNode nodeA = head;// 这个head是链表的的第一个元素
        ArrayList<Integer> listA = new ArrayList<>();
        ArrayList<Integer> listB = new ArrayList<>();
    
        while (nodeA != null) {
            if (nodeA.val < x) {
                listA.add(nodeA.val);
            } else {
                listB.add(nodeA.val);
            }
            nodeA = nodeA.next;
        }

        
        ListNode other = new ListNode(0);
        ListNode otherHead = other;

        for (int i = 0; i < listA.size(); i++) {
            ListNode tempA = new ListNode(listA.get(i));
            other.next = tempA;
            other = other.next;
        }

    
        for (int i = 0; i < listB.size(); i++) {
            ListNode tempB = new ListNode(listB.get(i));
            other.next = tempB;
            other = other.next;
        }

        return otherHead.next;

    }
}

第二种解法:

思路:
1

代码:

class Solution {
    public ListNode partition(ListNode head, int x) {
        ListNode small = new ListNode(0);
        ListNode smallHead = small;
        ListNode large = new ListNode(0);
        ListNode largeHead = large;
        while (head != null) {
            if (head.val < x) {
                small.next = head;
                small = small.next;
            } else {
                large.next = head;
                large = large.next;
            }
            head = head.next;
        }
        large.next = null;
        small.next = largeHead.next;
        return smallHead.next;
    }
}