链表二 链表常见算法题

目录

ListNode代码

链表中倒数最后k个结点

描述

        示例1

        示例2

解题思路

AC代码

不借助指针

快慢指针

删除链表中重复的结点

描述

示例1

示例2

解题思路

AC代码

可测试运行代码(需要ListNode代码,在文章开头):

运行结果


​​​​​​​链表一(基本概念和应用场景)+ 链表常见算法题-CSDN博客

ListNode代码


import java.util.Arrays;

public class ListNode {
    int val;
    ListNode next = null;

    public ListNode(int val) {
        this.val = val;
    }

    //遍历链表转换为字符串便于打印
    public String Traversal(ListNode listNode) {
        int[] arr = new int[getLength(listNode)];
        int i = 0 ;
        while (listNode != null){
            arr[i] = listNode.val;
            listNode = listNode.next;
            i++;
        }
        return Arrays.toString(arr);
    }
    // 获取长度
    public int getLength(ListNode head) {
        int length = 0;
        while (head != null) {
            length++;
            head = head.next;
        }
        return length;
    }
}

链表中倒数最后k个结点

描述

输入一个长度为 n 的链表,设链表中的元素的值为 ai ,返回该链表中倒数第k个节点。

如果该链表长度小于k,请返回一个长度为 0 的链表。

数据范围:0≤n≤105,0≤ai≤109,90≤k≤109

要求:空间复杂度 O(n),时间复杂度O(n)

进阶:空间复杂度 O(1),时间复杂度 O(n)

例如输入{1,2,3,4,5},2时,对应的链表结构如下图所示:

其中蓝色部分为该链表的最后2个结点,所以返回倒数第2个结点(也即结点值为4的结点)即可,系统会打印后面所有的节点来比较。

示例1

输入:{1,2,3,4,5},2

返回值:{4,5}

说明:返回倒数第2个节点4,系统会打印后面所有的节点来比较。

示例2

输入:{2},8

返回值:{}

解题思路

  1. 先算出链表的长度
  2. 算出到倒数第k个节点需要多少步
  3. 将指针移动指定步数,到达指定的节点。返回当前结点。

AC代码

不借助指针

public ListNode FindKthToTail (ListNode pHead, int k) {
        // write code here
        // 求出链表的长度
        int length = getLength(pHead);
        if(length < k){
            return null;
        }
        // 算出链表要走多少步
        int step = length - k;
//        // 定义一个指针
//        ListNode cur = pHead;
        // 移动相应步数找到需要返回的节点
        while(step != 0){
            pHead = pHead.next;
            step--;
        }
        return pHead;
    }
    //
    public int getLength(ListNode head){
        int length = 0;
        while(head != null){
            length++;
            head = head.next;
        }
        return length;
    }

快慢指针

public ListNode FindKthToTailByTwoPointer(ListNode pHead, int k){
        // 定义两个快慢指针
        ListNode fast = pHead;
        ListNode slow = pHead;
        // fast 先走k步
        while(k != 0){
            if (fast != null){
                // fast 往后走
                fast = fast.next;
                k--;
            }else {
                // 如果fast还没走到第k个位置 就是k大于链表长度,返回null
                return null;
            }
        }
        // 因为fast 先走k步,在保证两个指针一起走 他们的距离始终为k,
        // 当fast到链尾的时候 slow所在的位置就是倒数第k个节点
        while (fast != null){
            fast = fast.next;
            slow = slow.next;
        }
        // 
        return slow;
    }

删除链表中重复的结点

描述

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表 1->2->3->3->4->4->5 处理后为 1->2->5

数据范围:链表长度满足 0≤n≤1000 ,链表中的值满足 1≤val≤1000

进阶:空间复杂度 O(n) ,时间复杂度 O(n)

例如输入{1,2,3,3,4,4,5}时,对应的输出为{1,2,5},对应的输入输出链表如下图所示:

示例1

输入:{1,2,3,3,4,4,5}

返回值:{1,2,5}

示例2

输入:{1,1,1,8}

返回值:{8}

解题思路

  1. 使用两个工作指针 一个前赴(pre)指针在前,负责构建新的建表,一个当前(cur)指针去找重复节点的值,便于pre去连接。
  2. 总的来说就是去遍历链表,去寻找链表中重复出现的值,然后跳过这些值,使用pre去连接下一个节点值。
  3. 具体步骤如下代码:

AC代码

public class Solution {
    public ListNode deleteDuplication(ListNode pHead) {
        // 定义一个新的头节点 构建删除重复节点后的链表
        ListNode nHead = new ListNode(0);
        // 前赴指针
        ListNode pre = nHead;
        // 当前结点
        ListNode cur = pHead;
        // 将新的表头与pHead相连
        nHead.next = pHead;
        // 循环条件 要么当前节点为空 需要跳出循环 或者 工作指针到链尾需要跳出循环
        while(cur != null && cur.next != null){
            // 如果当前节点的值和下一个节点的值相等
            if(cur.next !=null && cur.val == cur.next.val ){
                // 持续找到连续重复的值一直移动指针 直到相邻两个节点的值不相等
                while(cur != null && cur.next != null && cur.val == cur.next.val ){
                    // 后移指针 
                    cur = cur.next;
                }
                // 移动到下一个暂时没有重复的节点值的位置
                cur = cur.next;
                // 将pre连接到重复节点的最后一个节点的后一个节点 
                // 这个操作相当于删除当前的有重复值的连续节点 直接连接到下一个暂时不是重复的节点位置
                pre.next = cur;
            }else{
                // pre跟着cur一起移动
                pre = cur;
                cur = cur.next;
            }
        }
        return nHead.next;
    }
}

可测试运行代码(需要ListNode代码,在文章开头):

public static void main(String[] args) {
        ListNode node = new ListNode(1);
        node.next = new ListNode(3);
        node.next.next = new ListNode(3);
        node.next.next.next = new ListNode(5);
        node.next.next.next.next = new ListNode(4);
        String before = node.Traversal(node);
        System.out.println("删除重复节点后的值为: " + before);

        ListNode listNode = deleteDuplication(node);
        String end = listNode.Traversal(listNode);
        System.out.println("删除重复节点后的值为: " + end);
    }

    public static ListNode deleteDuplication(ListNode pHead) {
        // 定义一个新的头节点 构建删除重复节点后的链表
        ListNode nHead = new ListNode(0);
        // 前赴指针
        ListNode pre = nHead;
        // 当前结点
        ListNode cur = pHead;
        // 将新的表头与pHead相连
        nHead.next = pHead;
        // 循环条件 要么当前节点为空 需要跳出循环 或者 工作指针到链尾需要跳出循环
        while(cur != null && cur.next != null){
            // 如果当前节点的值和下一个节点的值相等
            if(cur.val == cur.next.val ){
                // 持续找到连续重复的值一直移动指针 直到相邻两个节点的值不相等
                while(cur.next != null && cur.val == cur.next.val ){
                    // 后移指针
                    cur = cur.next;
                }
                // 移动到下一个暂时没有重复的节点值的位置
                cur = cur.next;
                // 将pre连接到重复节点的最后一个节点的后一个节点
                // 这个操作相当于删除当前的有重复值的连续节点 直接连接到下一个暂时不是重复的节点位置
                pre.next = cur;
            }else{
                // pre跟着cur一起移动
                pre = cur;
                cur = cur.next;
            }
        }
        return nHead.next;
    }

运行结果

图解

未完待续。。。。。。。。。。。。 

相关推荐

  1. 算法】114. 叉树展开为

    2024-07-12 14:30:06       44 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-12 14:30:06       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-12 14:30:06       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-12 14:30:06       58 阅读
  4. Python语言-面向对象

    2024-07-12 14:30:06       69 阅读

热门阅读

  1. Visual Studio 常用快捷键

    2024-07-12 14:30:06       24 阅读
  2. 【常用知识点-Linux】scp命令

    2024-07-12 14:30:06       21 阅读
  3. 用Redis写一个IP限流器

    2024-07-12 14:30:06       23 阅读
  4. 天童美语:推荐给孩子的人文历史纪录片

    2024-07-12 14:30:06       26 阅读
  5. 网站安全需求分析与安全保护工程

    2024-07-12 14:30:06       20 阅读
  6. 小米官网的数据是怎么优化的?

    2024-07-12 14:30:06       21 阅读
  7. 支付通道安全:应对黑客攻击的策略与实践

    2024-07-12 14:30:06       22 阅读
  8. Markdown 的详细语法介绍与使用

    2024-07-12 14:30:06       19 阅读
  9. OpenJudge | 比饭量

    2024-07-12 14:30:06       19 阅读