高频面试题:如何判断一个数组的单调性|Java 刷题打卡

简介: 高频面试题:如何判断一个数组的单调性|Java 刷题打卡

网络异常,图片无法展示
|


题目描述



这是 LeetCode 上的896. 单调数列


如果数组是单调递增或单调递减的,那么它是单调的。


  • 如果对于所有 i <= j,A[i] <= A[j],那么数组 A 是单调递增的。
  • 如果对于所有 i <= j,A[i]> = A[j],那么数组 A 是单调递减的。


当给定的数组 A 是单调数组时返回 true,否则返回 false。


示例 1:


输入:[1,2,2,3]
输出:true
复制代码


示例 2:


输入:[6,5,4,4]
输出:true
复制代码


示例 3:


输入:[1,3,2]
输出:false
复制代码


示例 4:


输入:[1,2,4,5]
输出:true
复制代码


示例 5:


输入:[1,1,1]
输出:true
复制代码


提示:


  • 1 <= A.length <= 50000
  • -100000 <= A[i] <= 100000


朴素解法(所谓的两次遍历)



两次遍历,分别检查是否为单调递增和单调递减。


class Solution {
    public boolean isMonotonic(int[] a) {
        return check(a, true) || check(a, false);
    }
    boolean check(int[] a, boolean flag) {
        for (int i = 0; i < a.length - 1; i++) {
            if (flag) {
                if (a[i] > a[i + 1]) return false;
            } else {
                if (a[i] < a[i + 1]) return false;
            }
        }
        return true;
    }
}
复制代码


  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(1)O(1)


朴素解法(所谓的一次遍历)



一次遍历。


同时为了防止扫完整个数组,增加一个提前 return 的逻辑:


class Solution {
    public boolean isMonotonic(int[] a) {
        boolean up = true, down = true;
        for (int i = 0; i < a.length - 1; i++) {
            if (a[i] > a[i + 1]) up = false;
            if (a[i] < a[i + 1]) down = false;
            if (!up && !down) return false;
        }
        return up || down;
    }
}
复制代码


  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(1)O(1)


总结



事实上,上述两种解法其实并不应该区分为「一次遍历」与「两次遍历」


我们应该用「对数组的访问次数」来定义遍历多少次,而不是「利用 for 循环的个数」来定义。上述无论那种方法,对数组访问次数都是一样的。


而在不对解法二进行剪枝的情况下,要比解法一慢。主要是因为解法一明确了是「递增」还是「递减」之后,在循环内部做了剪枝。


当我们对解法二进行同样的内部剪枝之后,其实和解法一应该是类似的。


前三次提交是保留 if (!up && !down) return false; 的提交 (1 ms)


后三次提交是不保留 if (!up && !down) return false; 的提交记录 (2 ms)


网络异常,图片无法展示
|


有趣的实验



在 LeetCode 上有位同学提出了一个很有意思的问题:如果数据量很大,大到内存都无法一次完全读入,那么一个循环里两次重复读应该比两次循环要快得多了吧?


我理解 ta 的意思是,每次读取值都算一次 IO 成本的话,一个循环里两次重复读的的成本应该是要小于比两次循环的成本吧?


因此有了以下的测试代码:


class Solution {
    // 统计「二次循环」的访问次数
    int cnt;
    public boolean isMonotonic(int[] a) {
        cnt = 0;
        // 这里不直接写成「短路与」进行返回,确保两个循环都会被执行
        boolean t = check(a, true), u = check(a, false); 
        System.out.println(cnt);
        return t || u;
    }
    boolean check(int[] a, boolean flag) {
        for (int i = 0; i < a.length - 1; i++) {
            if (flag) {
                if (getVal(a, i) > getVal(a, i + 1)) return false;
            } else {
                if (getVal(a, i) < getVal(a, i + 1)) return false;
            }
        }
        return true;
    }
    int getVal(int[] a, int idx) {
        cnt++;
        return a[idx];
    }
}
复制代码


对于样例数据的输出:8 8 6 8 8


class Solution {
    // 统计「一次循环」的访问次数
    int cnt;
    public boolean isMonotonic(int[] a) {
        cnt = 0;
        boolean up = true, down = true;
        for (int i = 0; i < a.length - 1; i++) {
            if (getVal(a, i) > getVal(a, i + 1)) up = false;
            if (getVal(a, i) < getVal(a, i + 1)) down = false;
            if (!up && !down) break;
        }
        System.out.println(cnt);
        return up || down;
    }
    int getVal(int[] a, int idx) {
        cnt++;
        return a[idx];
    }
}
复制代码


对于样例数据的输出:12 12 8 12 8


在样例数据中已经覆盖了递增、递减、常规数组、等值数组几种情况了,因此这个输出结果对比 我认为是具有普遍性的。存疑的同学可以写一个随机数组生成器去测试一下 ~


结论:二次循环的剪枝效果应该是要比一次循环要更好点(更加直接)。如果还有人坚持「所谓的一次循环」要优于「所谓的二次循环」,实验代码就是最好的证明。


最后



这是我们「刷穿 LeetCode」系列文章的第 No.* 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先将所有不带锁的题目刷完。


在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。


为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:github.com/SharingSour…


在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

相关文章
|
3月前
|
Java 测试技术 微服务
最新技术栈下 Java 面试高频技术点实操指南详解
本指南结合最新Java技术趋势,涵盖微服务(Spring Cloud Alibaba)、响应式编程(Spring WebFlux)、容器化部署(Docker+Kubernetes)、函数式编程、性能优化及测试等核心领域。通过具体实现步骤与示例代码,深入讲解服务注册发现、配置中心、熔断限流、响应式数据库访问、JVM调优等内容。适合备战Java面试,提升实操能力,助力技术进阶。资源链接:[https://pan.quark.cn/s/14fcf913bae6](https://pan.quark.cn/s/14fcf913bae6)
159 25
|
3月前
|
缓存 Java 关系型数据库
2025 年最新华为 Java 面试题及答案,全方位打造面试宝典
Java面试高频考点与实践指南(150字摘要) 本文系统梳理了Java面试核心考点,包括Java基础(数据类型、面向对象特性、常用类使用)、并发编程(线程机制、锁原理、并发容器)、JVM(内存模型、GC算法、类加载机制)、Spring框架(IoC/AOP、Bean生命周期、事务管理)、数据库(MySQL引擎、事务隔离、索引优化)及分布式(CAP理论、ID生成、Redis缓存)。同时提供华为级实战代码,涵盖Spring Cloud Alibaba微服务、Sentinel限流、Seata分布式事务,以及完整的D
165 1
|
2月前
|
缓存 Java API
Java 面试实操指南与最新技术结合的实战攻略
本指南涵盖Java 17+新特性、Spring Boot 3微服务、响应式编程、容器化部署与数据缓存实操,结合代码案例解析高频面试技术点,助你掌握最新Java技术栈,提升实战能力,轻松应对Java中高级岗位面试。
318 0
|
3月前
|
存储 安全 Java
常见 JAVA 集合面试题整理 自用版持续更新
这是一份详尽的Java集合面试题总结,涵盖ArrayList与LinkedList、HashMap与HashTable、HashSet与TreeSet的区别,以及ConcurrentHashMap的实现原理。内容从底层数据结构、性能特点到应用场景逐一剖析,并提供代码示例便于理解。此外,还介绍了如何遍历HashMap和HashTable。无论是初学者还是进阶开发者,都能从中受益。代码资源可从[链接](https://pan.quark.cn/s/14fcf913bae6)获取。
182 3
|
3月前
|
存储 安全 Java
2025 最新史上最全 Java 面试题独家整理带详细答案及解析
本文从Java基础、面向对象、多线程与并发等方面详细解析常见面试题及答案,并结合实际应用帮助理解。内容涵盖基本数据类型、自动装箱拆箱、String类区别,面向对象三大特性(封装、继承、多态),线程创建与安全问题解决方法,以及集合框架如ArrayList与LinkedList的对比和HashMap工作原理。适合准备面试或深入学习Java的开发者参考。附代码获取链接:[点此下载](https://pan.quark.cn/s/14fcf913bae6)。
958 48
|
3月前
|
算法 架构师 Java
Java 开发岗及 java 架构师百度校招历年经典面试题汇总
以下是百度校招Java岗位面试题精选摘要(150字): Java开发岗重点关注集合类、并发和系统设计。HashMap线程安全可通过Collections.synchronizedMap()或ConcurrentHashMap实现,后者采用分段锁提升并发性能。负载均衡算法包括轮询、加权轮询和最少连接数,一致性哈希可均匀分布请求。Redis持久化有RDB(快照恢复快)和AOF(日志更安全)两种方式。架构师岗涉及JMM内存模型、happens-before原则和无锁数据结构(基于CAS)。
95 5
|
3月前
|
Java API 微服务
2025 年 Java 校招面试全攻略:从面试心得看 Java 岗位求职技巧
《2025年Java校招最新技术要点与实操指南》 本文梳理了2025年Java校招的核心技术栈,并提供了可直接运行的代码实例。重点技术包括: Java 17+新特性(Record类、Sealed类等) Spring Boot 3+WebFlux响应式编程 微服务架构与Spring Cloud组件 Docker容器化部署 Redis缓存集成 OpenAI API调用 通过实际代码演示了如何应用这些技术,如Java 17的Record类简化POJO、WebFlux构建响应式API、Docker容器化部署。
125 5
|
3月前
|
缓存 NoSQL Java
Java Redis 面试题集锦 常见高频面试题目及解析
本文总结了Redis在Java中的核心面试题,包括数据类型操作、单线程高性能原理、键过期策略及分布式锁实现等关键内容。通过Jedis代码示例展示了String、List等数据类型的操作方法,讲解了惰性删除和定期删除相结合的过期策略,并提供了Spring Boot配置Redis过期时间的方案。文章还探讨了缓存穿透、雪崩等问题解决方案,以及基于Redis的分布式锁实现,帮助开发者全面掌握Redis在Java应用中的实践要点。
168 6
|
3月前
|
安全 Java API
2025 年 Java 校招面试常见问题及详细答案汇总
本资料涵盖Java校招常见面试题,包括Java基础、并发编程、JVM、Spring框架、分布式与微服务等核心知识点,并提供详细解析与实操代码,助力2025校招备战。
157 1
|
3月前
|
算法 Java 微服务
2025 年 Java 面试宝典社招春招秋招实操全方位攻略
2025年Java面试宝典涵盖核心技术及最新趋势,分为四大板块:1. Java基础:深入数据类型、多态等特性,结合学生信息管理等实例;2. JVM核心:解析内存模型与GC算法,附多线程转账等场景应用;3. 高并发方案:详解synchronized与线程池配置,提供Web服务器优化案例;4. Spring生态:剖析IoC/AOP原理,演示微服务架构实现。特别新增Java 17+特性实操,包括Record类、密封接口等语法糖,整合Spring Boot 3、响应式编程及云原生技术,通过订单状态机、API网关配置。
221 2

热门文章

最新文章