面试热题(回文链表)

news2024/12/26 12:37:16

给定一个链表的 头节点 head ,请判断其是否为回文链表。

如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。

       回文链表类似于回文串,正读倒读的顺序是一样的,那么我们怎么去判断一个链表是否是回文链表呢?

今天我们用多种方法、多种角度去思考问题,带你领略算法的奥秘

  • 字符串化比较

public boolean isPalindrome(ListNode head) {
        if(head==null){
            return false;
        }
        //一般通过StringBuilder进行字符操作
        StringBuilder s1=new StringBuilder();
        StringBuilder s2=new StringBuilder();
       //通过while循环将链表中的节点添加到字符串中
       while(head!=null){
           s1.append(head.val);
           s2.append(head.val);
           head=head.next;
       }
       //将s2进行翻转
       s2.reverse();
       return s1.toString().equals(s2.toString());}

       通过维护一个栈去保存链表中的节点,栈是先进后出的数据结构,这样也可以做到使得链表进行翻转,然后与原链表进行对比,得出正确的结果

 

 public boolean isPalindrome(ListNode head) {
        ListNode cur1=head;
        ListNode cur2=head;
        Stack<ListNode> stack=new Stack<>();
        while(cur1!=null){
            stack.add(cur1);
            cur1=cur1.next;
        }
        while(cur2!=null&&!stack.isEmpty()){
            ListNode curNode=stack.pop();
            if(curNode.val!=cur2.val){
                return false;
            }
            cur2=cur2.next;
        }
        return true;
    }

  • 中点翻转对比

 链表为偶数时:                                                           链表为奇数时:

  1.  通过快慢指针找到链表的中心点
    public ListNode findMid(ListNode head){
            ListNode fast=head;
            ListNode slow=head;
            //快慢指针,快走两步,慢走一步,最后slow的位置就是链表的中心点
            while(fast.next!=null&&fast.next.next!=null){
                fast=fast.next.next;
                slow=slow.next;
            }
            return slow;
        }
  2. 将中心点后面的链表进行翻转
    public ListNode reverseList(ListNode head){
            if(head==null){
                return head;
            }
            //前驱
            ListNode pre=null;
            //当前节点
            ListNode cur=head;
            //后继
            ListNode next=null;
            while(cur!=null){
             next=cur.next;
             cur.next=pre;
             pre=cur;
             cur=next;
            }
            //返回前驱
            return pre;
        }
  3. 判断前半段链表和后半段链表是否相等
    public boolean isSame(ListNode l1,ListNode l2){
            ListNode p1=l1;
            ListNode p2=l2;
            //这里只能判断p2,因为p1d的话,它上半段遍历完,它会接着遍历下半段
            while(p2!=null){
                if(p1.val!=p2.val){
                    return false;
                }
                p1=p1.next;
                p2=p2.next;
            }
            return true;
        }

 源码:

public boolean isPalindrome(ListNode head) {
       if(head==null){
           return true;
       }
       ListNode mid=findMid(head);
       ListNode l1=head;
       ListNode l2=mid.next;
       l2=reverseList(l2);
       return isSame(l1,l2);
    }
    public ListNode findMid(ListNode head){
        ListNode fast=head;
        ListNode slow=head;
        while(fast.next!=null&&fast.next.next!=null){
            fast=fast.next.next;
            slow=slow.next;
        }
        return slow;
    }

    public ListNode reverseList(ListNode head){
        if(head==null){
            return head;
        }
        ListNode pre=null;
        ListNode cur=head;
        ListNode next=null;
        while(cur!=null){
         next=cur.next;
         cur.next=pre;
         pre=cur;
         cur=next;
        }
        return pre;
    }
    public boolean isSame(ListNode l1,ListNode l2){
        ListNode p1=l1;
        ListNode p2=l2;
        while(p2!=null){
            if(p1.val!=p2.val){
                return false;
            }
            p1=p1.next;
            p2=p2.next;
        }
        return true;
    }

 

  • 双端队列

通过维护一个双端队列去进行操作,所谓的双端队列就是可以从队尾进,也可以从队头进

 while(head!=null){
          queue.addLast(head);
          head=head.next;
      }

       将链表中的元素都塞入双端队列中,结束后,同时从队头队尾取节点,判断是否相等(相当于反向双指针)

          ListNode h=queue.removeFirst();
          ListNode t=queue.removeLast();
          if(h.val!=t.val){
              return false;
          }

 链表的节点为偶数时:

 

 链表的节点为偶数时:

 所以循环的结束条件则为:

while(queue.size()>1){
    ...
}

  • 递归(链表递归相互奔向)

 

       递归到最后一个结点直接返回,与当前节点比较,如果相等,当前节点往后移动一位,递归再返回,这种就可以做到从两边进行比较

private void dfs(ListNode head, ListNode phead, boolean res) {
        if (head == null || !res) {
            return;
        }
        dfs(head.next, phead, res);
        if (head.val != phead.val) {
            res = false;
        }
        phead = phead.next;  
    }
    public boolean isPalindrome(ListNode head) {
        boolean res = true;
        ListNode phead = head;
        dfs(head, phead, res);
        return res;
    }

你们觉得这个代码有问题么?

       测试的结果都是true,说明我们这个过程并没有改变我们res的默认值,因为我们的java是值传递,并不是引用传递,所以并不会改变我们的值,所以我们需要将res、遍历的节点分别封装成一个对象进行传递

 private void dfs(ListNode head, ListNode[] phead, boolean[] res) {
        if (head == null || !res[0]) {
            return;
        }
        dfs(head.next, phead, res);
        if (head.val != phead[0].val) {
            res[0] = false;
        }
        phead[0] = phead[0].next;
    }

    public boolean isPalindrome(ListNode head) {
        boolean[] res = {true};
        ListNode[] phead = {head};
        dfs(head, phead, res);
        return res[0];
    }

       这几种方式已经全部介绍结束,希望大家做题的时候,不要死记住一种解法去解决问题,多思考别的方式,拓宽自己的思路,不局限于一种解法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/873683.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

7.2.tensorRT高级(2)-学习深度学习中涉及的线程知识

目录 前言1. 多线程2. 问答环节2.1 线程启动相关问题2.2 线程启动函数参数相关问题 总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次…

7. 延迟队列

延迟队列 7.1. 延迟队列概念 延时队列,队列内部是有序的&#xff0c;最重要的特性就体现在它的延时属性上&#xff0c;延时队列中的元素是希望 在指定时间到了以后或之前取出和处理&#xff0c;简单来说&#xff0c;延时队列就是用来存放需要在指定时间被处理的 元素的队列。 7…

第二章-算法

第二章-算法 数据结构和算法的关系 算法是解决特定问题求解步骤的描述&#xff0c;在计算机中表现为指令的有限序列&#xff0c;并且每条指令表示一个或多个操作。 算法的特性 算法有五个基本特征&#xff1a;输入、输出、有穷性、确定性和可行性。 输入&#xff1a;算法具…

LVS集群和nginx负载均衡

目录 1、基于 CentOS 7 构建 LVS-DR 群集。 2、配置nginx负载均衡。 1、基于 CentOS 7 构建 LVS-DR 群集。 1.部署LVS负载调度器 1>安装配置工具 [rootnode6 ~]# yum install -y ipvsadm 2>配置LVS虚拟IP&#xff08;VIP地址&#xff09; [rootnode6 ~]# ifconfig ens…

Tesseract用OpenCV进行文本检测

我没有混日子&#xff0c;只是辛苦的时候没人看到罢了 一、什么是Tesseract Tesseract是一个开源的OCR&#xff08;Optical Character Recognition&#xff09;引擎&#xff0c;OCR是一种技术&#xff0c;它可以识别和解析图像中的文本内容&#xff0c;使计算机能够理解并处理…

Dalsa线阵相机说明(Linea Color GigESeries 2k and 4K)

文章目录 一. Dalsa相机软件整体架构二. 相机编号说明以及软件要求三. 相机硬件参数三. 相机基本参数四. 软件参数设置列表1. Sensor Control Category2. I/O Control Category3. Counter and Timer Control Category4. Advanced Processing Control Category(1) 平场校正介绍(…

蚂蚁聚合支付系统源码完美版+附安装教程

这是我上个月花重金购买的四fang系统源码&#xff0c;现在分享给大家。 源码内附安装教程&#xff0c;20多项功能及安全方面的更新文档&#xff0c;源码说明等&#xff0c;小白也能轻松搭建。 能够轻松应对高并发&#xff0c;等以前版本无法应对的并发问题&#xff0c;也不会被…

JIRA:项目管理的秘密武器

引言 在当今动态且快速变化的商业环境中&#xff0c;项目管理已经成为任何组织成功的关键因素。能够有效地管理项目&#xff0c;保证项目在设定的时间和预算内按照预期的质量完成&#xff0c;是每个项目经理的目标。为了实现这个目标&#xff0c;项目经理需要依赖强大的工具&a…

由于找不到vcruntime140_1.dll,无法继续执行代码该怎么修复呢?

我最近遇到了一个vcruntime140_1.dll的问题&#xff0c;导致我的某些应用程序无法正常运行。当我第一次遇到这个问题时&#xff0c;我对这个dll文件的作用一无所知。我开始搜索并了解了vcruntime140_1.dll是Microsoft Visual C Redistributable的一部分&#xff0c;并为使用Vis…

FreeRTOS(计数信号量)

资料来源于硬件家园&#xff1a;资料汇总 - FreeRTOS实时操作系统课程(多任务管理) 目录 一、计数信号量的定义与应用 1、计数信号量的定义 2、计数信号量的应用 二、计数信号量的运作机制 1、任务间计数信号量的实现 三、计数信号量常用的API函数 1、计数信号量典型流程…

泛型编程| 模板初阶——懒人福音!

目录 前言介绍 函数模板 函数模板格式 函数模板的原理 函数模板的实例化 隐式实例化 显示实例化 模板参数匹配规则 类模板 总结 前言介绍 之前c语言实现swap函数的时候&#xff0c;我们不仅要修改参数的类型&#xff0c;还要修改函数的名字 而在学完函数重载之后&am…

东南大学齿轮箱故障诊断(Python代码,MSCNN结合LSTM结合注意力机制模型,代码有注释)

运行代码要求&#xff1a; 代码运行环境要求&#xff1a;Keras版本>2.4.0&#xff0c;python版本>3.6.0 1.东南大学采集数据平台&#xff1a; 数据 该数据集包含2个子数据集&#xff0c;包括轴承数据和齿轮数据&#xff0c;这两个子数据集都是在传动系动力学模拟器&am…

Android JNI实现锅炉压力显示系统详解

前些天发现了一个蛮有意思的人工智能学习网站,8个字形容一下"通俗易懂&#xff0c;风趣幽默"&#xff0c;感觉非常有意思,忍不住分享一下给大家。 &#x1f449;点击跳转到教程 第一步创建GuoLu.c文件 // // Created by DELL on 2023/8/13. // #include <stdio.h…

Python 潮流周刊#15:如何分析 FastAPI 异步请求的性能?

你好&#xff0c;我是猫哥。这里每周分享优质的 Python、AI 及通用技术内容&#xff0c;大部分为英文。标题取自其中一则分享&#xff0c;不代表全部内容都是该主题&#xff0c;特此声明。 本周刊精心筛选国内外的 250 信息源&#xff0c;为你挑选最值得分享的文章、教程、开源…

记录一下关于word存放代码出现的问题

如下图所示&#xff0c;从 Word 中复制代码并粘贴到其他地方&#xff0c;例如文本编辑器或代码编辑器中&#xff0c;有时会出现额外的连字符或破折号。这是因为 Word 使用了特定的字符编码和格式&#xff0c;而这些字符在代码中可能不被支持或解析为特殊字符。   可见有时从…

Java线程调度以及算法

线程调度概况 Java的线程调度程序是JVM的一部分&#xff0c;它决定应该运行哪个线程。无法保证线程调度程序将选择运行哪个可运行线程。 一次只能有一个线程在一个进程中运行。线程调度程序主要使用抢占式或时间切片调度来调度线程。 抢占式调度与时间分片的区别 在抢占式调…

边缘计算:下一代计算模式的突破

章节一&#xff1a;引言 随着物联网、人工智能和大数据等技术的不断发展&#xff0c;计算需求变得越来越复杂&#xff0c;传统的云计算模式已经难以满足快速增长的数据处理需求。在这样的背景下&#xff0c;边缘计算作为一种全新的计算模式崭露头角&#xff0c;为我们带来了更加…

Pytorch深度学习-----实现神经网络模型在GPU上进行训练的方法

系列文章目录 PyTorch深度学习——Anaconda和PyTorch安装 Pytorch深度学习-----数据模块Dataset类 Pytorch深度学习------TensorBoard的使用 Pytorch深度学习------Torchvision中Transforms的使用&#xff08;ToTensor&#xff0c;Normalize&#xff0c;Resize &#xff0c;Co…

css3新增选择器总结

目录 一、属性选择器 二、结构伪类选择器 三、伪元素选择器 四、UI状态伪类选择器 五、反选伪类选择器 六、target选择器 七、父亲选择器、后代选择器 八、相邻兄弟选择器、兄弟们选择器 一、属性选择器 &#xff08;除IE6外的大部分浏览器支持&#xff09; E&#…

数据库设计,理解第二范式和第三范式的区别

在学习数据库范式的时候&#xff0c;很多人搞不清第二范式和第三范式他到底是有啥区别。 想讲清楚第二范式与第三范式的区别&#xff0c;不得不聊到键和相关属性的概念 键和相关属性的概念 范式的定义会使用到主健和候选健&#xff0c;数据库中的健&#xff08;Key)由一个或…