力扣最热一百题——轮转数组

news2025/1/12 23:10:27

目录

题目链接:189. 轮转数组 - 力扣(LeetCode)

题目描述

示例

提示:

知识补充ArrayDeque ()

ArrayDeque 的特点:

常用方法:

详细示例:

运行结果:

总结:

解法一:使用队列模拟

Java写法:

运行时间

C++写法:

运行时间

​编辑

解法二:三次翻转数组+双指针

Java写法:

运行时间

C++写法

 运行时间

总结


题目链接:189. 轮转数组 - 力扣(LeetCode)

注:下述题目描述和示例均来自力扣

题目描述

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例

示例 1:

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]

示例 2:

输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释: 
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]

提示:

  • 1 <= nums.length <= 10^{5}
  • -2^{31} <= nums[i] <= 2^{31} - 1
  • 0 <= k <= 10^{5}

知识补充ArrayDeque ()

        ArrayDeque 是 Java 提供的一个基于数组实现的双端队列(deque),全名是 "Array Double Ended Queue"。它是 Deque 接口的实现之一,既可以用作队列(FIFO,先进先出),也可以用作栈(LIFO,后进先出)。它底层基于循环数组实现,具有较高的效率,可以在队列两端进行快速的插入和删除操作。

ArrayDeque 的特点:

  1. 双端操作

    • ArrayDeque 允许我们在队列的头部和尾部同时进行元素的添加和删除操作,这使得它既能模拟队列,又能模拟栈。
    • 由于它是一个双端队列,因此可以灵活使用栈和队列的典型操作。
  2. 动态数组扩展

    • 底层是基于循环数组实现的。当数组满了时,ArrayDeque 会自动扩容(通常会加倍数组大小),因此无需担心容量问题。
    • 相比于 LinkedListArrayDeque 的扩容代价相对较低,因为它直接在数组中操作数据,而无需额外的节点对象和指针。
  3. 高效操作

    • 插入和删除操作的时间复杂度都是 O(1),不涉及复杂的指针操作,因此效率非常高。
    • 不建议使用 ArrayDeque 来做随机访问(比如通过索引访问某个元素),因为这是线性时间操作 O(n),适合的场景是作为队列或栈使用。
  4. 线程不安全

    • ArrayDeque 不是线程安全的,如果在多线程环境中使用,需要自行实现同步机制,比如通过 synchronized 块或使用并发队列如 ConcurrentLinkedDeque

常用方法:

  • 添加元素

    • offer(E e):将元素添加到队列的尾部(队列特性)。
    • offerFirst(E e):将元素添加到队列的头部(双端队列特性)。
    • offerLast(E e):将元素添加到队列的尾部,和 offer 相同。
  • 移除元素

    • poll():移除并返回队列头部的元素(队列特性),如果队列为空,返回 null
    • pollFirst():移除并返回队列头部的元素(双端队列特性)。
    • pollLast():移除并返回队列尾部的元素。
  • 获取元素

    • peek():返回队列头部的元素但不移除它(队列特性),如果队列为空,返回 null
    • peekFirst():返回队列头部的元素但不移除它(双端队列特性)。
    • peekLast():返回队列尾部的元素但不移除它。
  • 栈操作

    • push(E e):将元素压入栈顶(相当于 addFirst 操作,栈特性)。
    • pop():移除并返回栈顶元素(相当于 pollFirst 操作,栈特性)。

详细示例:

 
import java.util.ArrayDeque;

public class ArrayDequeExample {
    public static void main(String[] args) {
        // 创建一个ArrayDeque
        ArrayDeque<Integer> deque = new ArrayDeque<>();

        // 队列操作
        deque.offer(10); // 添加到尾部
        deque.offer(20); // 添加到尾部
        deque.offer(30); // 添加到尾部

        System.out.println("队列内容: " + deque);

        // 出队操作(FIFO,先进先出)
        int firstElement = deque.poll(); // 移除并返回头部元素
        System.out.println("出队元素: " + firstElement);
        System.out.println("队列剩余内容: " + deque);

        // 栈操作
        deque.push(40); // 将元素压入栈顶
        deque.push(50); // 将元素压入栈顶

        System.out.println("栈内容: " + deque);

        // 出栈操作(LIFO,后进先出)
        int topElement = deque.pop(); // 移除并返回栈顶元素
        System.out.println("出栈元素: " + topElement);
        System.out.println("栈剩余内容: " + deque);
    }
}

运行结果:

队列内容: [10, 20, 30]
出队元素: 10
队列剩余内容: [20, 30]
栈内容: [50, 40, 20, 30]
出栈元素: 50
栈剩余内容: [40, 20, 30]

总结:

  • ArrayDeque 非常适合作为队列和栈使用,因为它提供了高效的双端插入、删除操作。
  • ArrayDeque 相较于 LinkedList 来说在大多数场景下更高效,尤其是在不涉及频繁的随机访问时。
  • 它是 Deque 接口的常用实现,灵活且高效。


解法一:使用队列模拟

Java写法:

class Solution {
    public void rotate(int[] nums, int k) {
        /**
                        1,2,3,4,5,6,7
         向右轮转 1 步: [7,1,2,3,4,5,6]
         向右轮转 2 步: [6,7,1,2,3,4,5]
         向右轮转 3 步: [5,6,7,1,2,3,4]
         */
         // 创建一个队列准备模拟这个过程
        ArrayDeque<Integer> deque = new ArrayDeque<>();
        // 将数组中的值都添加进入队列中
        for (int num : nums) {
            deque.offer(num);
        }

        // 轮转K次
        for (int i = 1; i <= k; i++) {
            Integer last = deque.pollLast();
            deque.offerFirst(last);
        }
        // 再重新更新数组中的值
        int i = 0;
        for (Integer integer : deque) {
            nums[i] = integer;
            i++;
        }
    }
}
运行时间

C++写法:

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
// 如果k大于数组长度,则取模简化问题  
        k %= nums.size();  
        if (k == 0) return; // 如果k为0,则无需旋转  
  
        // 创建一个deque准备模拟这个过程  
        std::deque<int> deque(nums.begin(), nums.end());  
  
        // 轮转K次  
        for (int i = 0; i < k; i++) {  
            int last = deque.back(); // 取出最后一个元素  
            deque.pop_back(); // 从deque尾部删除元素  
            deque.push_front(last); // 将取出的元素插入到deque的头部  
        }  
  
        // 再重新更新数组中的值  
        int i = 0;  
        for (int num : deque) {  
            nums[i++] = num;  
        }  
    }  
};
运行时间

挺慢的但你就说过没过吧




解法二:三次翻转数组+双指针

Java写法:

class Solution {
    public void rotate(int[] nums, int k) {
        /**
            1,2,3,4,5,6,7
            7,6,5,4,3,2,1
            分别翻转
            5,6,7,   1,2,3,4
         */
        int len = nums.length;
        // 如果k>len了那么只需要取余,因为轮转len个位置等于没有轮转
        if(k > len){
            k %= len;
        }
        // 先整体的翻转一下
        reverseArray(nums,0,len - 1);
        // 翻转前k位
        reverseArray(nums,0,k - 1);
        // 翻转剩下的
        reverseArray(nums,k,len - 1);
        
    }

    /**
     * 翻转数组的指定位置
     * @param arr 目标数组
     * @param start 翻转起始索引
     * @param end 翻转结束索引
     */
    public void reverseArray(int[] arr,int start,int end){
        // 利用前后两个指针来交换(也就是翻转数组)
        while (start < end){
            int temp = arr[start];
            arr[start] = arr[end];
            arr[end] = temp;
            // 移动指针
            start++;
            end--;
        }
    }
}
运行时间

C++写法

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int len = nums.size();  
        // 如果k>len了那么只需要取余,因为轮转len个位置等于没有轮转  
        k = k % len;  
          
        // 先整体的翻转一下  
        reverseArray(nums, 0, len - 1);  
        // 翻转前k位  
        reverseArray(nums, 0, k - 1);  
        // 翻转剩下的  
        reverseArray(nums, k, len - 1);  
    }  
  
    /**  
     * 翻转数组的指定位置  
     * @param arr 目标数组  
     * @param start 翻转起始索引  
     * @param end 翻转结束索引  
     */  
    void reverseArray(std::vector<int>& arr, int start, int end) {  
        // 利用前后两个指针来交换(也就是翻转数组)  
        while (start < end) {  
            std::swap(arr[start], arr[end]);  
            // 移动指针  
            start++;  
            end--;  
        }  
    }  
};
 运行时间


总结

        其实我觉得直接使用队列还是更好理解更加的简单,虽然优化只是一个翻转数组但是也是极其的简单的操作。

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

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

相关文章

无刷直流电动机的匝间绝缘测试优化

近年来&#xff0c;随着消费者对高效、快速干发需求的增加&#xff0c;高速电吹风逐渐成为市场的宠儿。高速电吹风的关键技术之一便是无刷直流电动机&#xff0c;其转速可以高达100,000转/分钟以上&#xff0c;电压为DC310V。相比传统电吹风&#xff0c;高速电吹风在效率和用户…

java基于PDF底层内容流的解析对文本内容进行编辑

本文实现了基于坐标位置对PDF内容的底层修改而非覆盖&#xff0c;因此不会出现在某些高级PDF编辑器中可以移除插入内容或者文件随着编辑次数增多而大幅增大&#xff08;原因是原内容还在文件中&#xff09;的问题&#xff0c;而且使用的pdfbox是一个开源的、免费的PDF处理库&am…

如何使用 Vidu Studio 根据照片和提示词生成视频

在这个数字化时代&#xff0c;视频内容已经成为我们日常生活中不可或缺的一部分。无论是记录美好瞬间&#xff0c;还是制作创意短片&#xff0c;视频都能生动地呈现我们的故事。今天&#xff0c;我将向大家介绍如何使用 Vidu Studio&#xff0c;根据已有照片和提示词&#xff0…

保姆级CVE-2018-17066漏洞复现 DLink命令注入漏洞(更新完结)

参考文章 CVE-2018-17066复现-CSDN博客 IOT-CVE-2018-17066(D-Link命令注入漏洞)_firmae路由仿真-CSDN博客 https://www.cnblogs.com/from-zero/p/13300396.html IOT-CVE-2018-17066(D-Link命令注入漏洞)_iot设备漏洞-CSDN博客 cve-2018-17066复现 | 1uckycs blog 漏洞环境搭建…

web渗透—RCE

一&#xff1a;代码执行 相关函数 1、eval()函数 assert()函数 (1)原理&#xff1a;将用户提交或者传递的字符串当作php代码执行 (2)passby:单引号绕过&#xff1a;闭合注释&#xff1b;开启GPC的话就无法绕过&#xff08;GPC就是将单引号转换为"反斜杠单引号"&a…

【Redis】缓存和数据库一致性问题及解决方案

往期文章&#xff1a; 【Redis】Redis 底层的数据结构&#xff08;结合源码&#xff09; 【Redis】为什么选择 Redis 做缓存&#xff1f; 【Redis】缓存击穿、缓存穿透、缓存雪崩原理以及多种解决方案 一、前言 在前面的文章中&#xff0c;我们探讨了为什么要使用 Redis…

独居打工人,把超市当顶配食堂

文 | 螳螂观察 作者 | 如意 独自在大城市扎根的年轻人有着自己的小确幸&#xff0c;比如“周末可以睡到下午才起床&#xff0c;不会有任何人打扰”&#xff0c;“瘫在沙发上吃着零食享受一部自己想看很久的电影&#xff0c;也不会被唠叨。” 但生活并不总是尽如人意&#xf…

基于SpringBoot+Vue的学生宿舍水电信息管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的…

PDF在线编辑哪家强?2024年4款热门工具大比拼

如今是数字化的时代&#xff0c;PDF 文件对我们工作和学习来说特别重要。不过呢&#xff0c;遇到那些麻烦的 PDF 编辑和转换的事情时&#xff0c;你是不是常常觉得没招儿&#xff0c;甚至还得加班到半夜&#xff1f;别犯愁啦&#xff0c;今天我给你讲讲四款非常好用的 PDF 在线…

深入理解全连接层:从线性代数到 PyTorch 中的 nn.Linear 和 nn.Parameter

文章目录 数学概念&#xff08;全连接层&#xff0c;线性层&#xff09;nn.Linear()nn.Parameter()Q1. 为什么 self.weight 的权重矩阵 shape 使用 ( out_features , in_features ) (\text{out\_features}, \text{in\_features}) (out_features,in_features)而不是 ( in_featur…

【人工智能】OpenAI最新发布的GPT-o1模型,和GPT-4o到底哪个更强?最新分析结果就在这里!

在人工智能的快速发展中&#xff0c;OpenAI的每一次新模型发布都引发了广泛的关注与讨论。2023年9月13日&#xff0c;OpenAI正式推出了名为o1的新模型&#xff0c;这一模型不仅是其系列“推理”模型中的首个代表&#xff0c;更是朝着类人人工智能迈进的重要一步。本文将综合分析…

10款超好用的电脑文件加密软件推荐|2024文件加密软件排行榜

在数字时代&#xff0c;数据安全已成为个人和企业不可忽视的重要议题。加密软件作为守护数据安全的坚固防线&#xff0c;其重要性不言而喻。以下是2024年备受推荐的十款电脑文件加密软件。 1.安秉网盾 安秉网盾以其全面的数据保护和安全防护功能备受企业青睐。它支持多种加密…

C语言内存函数(21)

文章目录 前言一、memcpy的使用和模拟实现二、memmove的使用和模拟实现三、memset函数的使用四、memcmp函数的使用总结 前言 正文开始&#xff0c;发车&#xff01; 一、memcpy的使用和模拟实现 函数模型&#xff1a;void* memcpy(void* destination, const void* source, size…

深入Redis:分布式锁

在一个分布式的系统中&#xff0c;会涉及到多个节点访问同一个公共资源的情况。此时就需要通过锁来做互斥控制&#xff0c;避免出现类似于“线程安全”的问题。 Java中的synchronize只能在当前线程中生效&#xff0c;在分布式的这种多个进程多个主机的场景下就无能为力了。此时…

原型模式详细介绍和代码实现

&#x1f3af; 设计模式专栏&#xff0c;持续更新中&#xff0c; 欢迎订阅&#xff1a;JAVA实现设计模式 &#x1f6e0;️ 希望小伙伴们一键三连&#xff0c;有问题私信都会回复&#xff0c;或者在评论区直接发言 Java实现原型模式 介绍: 原型模式&#xff08;Prototype Patte…

C4D2025来了!亮眼的新功能一览

C4D2025新功能亮点&#xff0c;同步上新的Redshift 2025.0.2。等我体验了再给大家讲详细的 成都渲染101云渲染支持对应软件渲染&#xff0c;3090等显卡&#xff0c;云渲码6666 渲染101云渲码6666 Mograph增强 引入线性域标签&#xff0c;用于精细控制对象参数。 为追踪器对象新…

安泰功率放大器有哪些特点呢

功率放大器是电子设备中的重要组成部分&#xff0c;其作用是将输入信号的电功率放大到足够的水平&#xff0c;以驱动负载&#xff0c;如扬声器或天线。功率放大器有一些独特的特点&#xff0c;这些特点对于各种应用至关重要。下面将详细介绍功率放大器的特点&#xff0c;以更好…

【Vue】移动端访问Vue项目页面无数据,但是PC访问有数据

问题&#xff1a; Vue项目&#xff0c;PC访问时下拉列表有数据&#xff0c;移动端访问时下拉列表没有数据&#xff1b; 思路&#xff1a; 首先打开了Fiddler抓包工具&#xff0c;把抓到的url复制到PC浏览器进行访问&#xff0c;结果发现PC上访问这个页面是有数据的&#xff…

利用Leaflet.js创建交互式地图:绘制固定尺寸的长方形

在现代Web开发中&#xff0c;交互式地图已成为展示地理位置数据的重要工具。Leaflet.js是一个轻量级、功能丰富的开源JavaScript库&#xff0c;用于构建移动友好的交互式地图。在本文中&#xff0c;我们将探讨如何利用Leaflet.js在地图上绘制一个固定尺寸的长方形&#xff0c;扩…

堆+堆排序+topK问题

目录 堆&#xff1a; 1、堆的概念 2、堆的结构 3、堆的实现 3.1、建堆 3.1.1、向上调整建堆(用于堆的插入) 3.1.2、向下调整建堆 3.2、堆的删除 3.3、堆的代码实现 3.3.1、Heap.h 3.3.2、Heap.c 堆排序&#xff1a;&#xff08;O(N*log(N))&#xff09; 1、排序如何…