轮转数组[中等]

news2024/10/12 18:19:32

优质博文:IT-BLOG-CN

一、题目

给定一个整数数组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 <= 105
-231 <= nums[i] <= 231 - 1
0 <= k <= 105

进阶: 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。你可以使用空间复杂度为O(1)的原地算法解决这个问题。

二、代码

【1】使用额外的数组: 我们可以使用额外的数组来将每个元素放至正确的位置。我们遍历原数组,将原数组下标为i的元素放至新数组下标为(i+k) mod nums.length的位置,最后将新数组拷贝至原数组即可。

class Solution {
    public void rotate(int[] nums, int k) {
        // 使用一个等长的数组
        int[] newArray = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            newArray[(i + k) % nums.length] = nums[i];
        }
        System.arraycopy(newArray, 0, nums, 0, nums.length);
    }
}

时间复杂度: O(n)其中n为数组的长度。
空间复杂度: O(n)

【2】数组翻转: 该方法基于如下的事实:当我们将数组的元素向右移动k次后,尾部k mod n个元素会移动至数组头部,其余元素向后移动k mod n个位置。

该方法为数组的翻转: 我们可以先将所有元素翻转,这样尾部的k mod n个元素就被移至数组头部,然后我们再翻转[0,k mod n−1]区间的元素和[k mod n,n−1]区间的元素即能得到最后的答案。

我们以n=7k=3为例进行如下展示:

操作结果
原始数组1 2 3 4 5 6 7
翻转所有元素7 6 5 4 3 2 1
翻转[0,k mod n−1]区间的元素5 6 7 4 3 2 1
翻转 [k mod n,n−1]区间的元素5 6 7 1 2 3 4
class Solution {
    public void rotate(int[] nums, int k) {
        // 放置下表越界
        k %= nums.length;
        // 数组反转
        reverse(nums, 0 , nums.length - 1);
        reverse(nums, 0, k - 1);
        reverse(nums, k, nums.length - 1);
    }

    private void reverse(int[] nums, int start, int end) {
        while(start < end) {
            int temp = nums[start];
            nums[start] = nums[end];
            nums[end] = temp;
            ++start;
            --end;
        }
    }
}

【3】环状替换: 方法一中使用额外数组的原因在于如果我们直接将每个数字放至它最后的位置,这样被放置位置的元素会被覆盖从而丢失。因此,从另一个角度,我们可以将被替换的元素保存在变量temp中,从而避免了额外数组的开销。

我们从位置0开始,最初令temp=nums[0]。根据规则,位置0的元素会放至(0+k) mod n的位置,令x=(0+k) mod n,此时交换tempnums[x],完成位置x的更新。然后,我们考察位置x,并交换tempnums[(x+k) mod n],从而完成下一个位置的更新。不断进行上述过程,直至回到初始位置0

容易发现,当回到初始位置0时,有些数字可能还没有遍历到,此时我们应该从下一个数字开始重复的过程,可是这个时候怎么才算遍历结束呢?我们不妨先考虑这样一个问题:从0开始不断遍历,最终回到起点0的过程中,我们遍历了多少个元素?由于最终回到了起点,故该过程恰好走了整数数量的圈,不妨设为a圈;再设该过程总共遍历了b个元素。因此,我们有an=bk,即an一定为n,k的公倍数。又因为我们在第一次回到起点时就结束,因此a要尽可能小,故an就是n,k的最小公倍数lcm(n,k),因此b就为lcm(n,k)/k

这说明单次遍历会访问到lcm(n,k)/k个元素。为了访问到所有的元素,我们需要进行遍历的次数为n/(lcm(n,k)/k)=nk/(lcm(n,k))=gcd(n,k)

其中gcd指的是最大公约数。

我们用下面的例子更具体地说明这个过程:

nums = [1, 2, 3, 4, 5, 6]
k = 2

在这里插入图片描述

如果读者对上面的数学推导的理解有一定困难,也可以使用另外一种方式完成代码:使用单独的变量count跟踪当前已经访问的元素数量,当count=n时,结束遍历过程。

class Solution {
    public void rotate(int[] nums, int k) {
        int n = nums.length;
        k = k % n;
        int count = gcd(k, n);
        for (int start = 0; start < count; ++start) {
            int current = start;
            int prev = nums[start];
            do {
                int next = (current + k) % n;
                int temp = nums[next];
                nums[next] = prev;
                prev = temp;
                current = next;
            } while (start != current);
        }
    }

    public int gcd(int x, int y) {
        return y > 0 ? gcd(y, x % y) : x;
    }
}

时间复杂度: O(n)其中n为数组的长度。每个元素只会被遍历一次。
空间复杂度: O(1)我们只需常数空间存放若干变量。

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

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

相关文章

VMware安装银河麒麟高级服务器操作系统V10

目标 VMware安装银河麒麟高级服务器操作系统V10背景介绍环境准备安装步骤配置VM虚拟机系统安装 VMware安装银河麒麟高级服务器操作系统V10 背景介绍 近期&#xff0c;随着国产信创的持续发热和大众关注度的上升&#xff0c;我们公司决定与时俱进&#xff0c;针对国产技术趋势…

【使用OpenCV进行目标分割与计数的代码实例详解】

文章目录 概要实例一&#xff1a;硬币分割计数实例二&#xff1a;玉米粒分割计数 概要 在当今数字图像处理领域&#xff0c;图像分割技术是一项至关重要的任务。图像分割旨在将图像中的不同目标或区域准确地分开&#xff0c;为计算机视觉、图像识别和机器学习等领域提供了坚实…

javascript/python 笔记: folium feature group自动切换

1 python部分 python部分只能是静态的结果 1.1 导入库 import folium import math 1.2 数据 cell_lst表示基站位置&#xff0c;location_lst表示 用户实际位置&#xff08;均为伪数据&#xff09; cell_lst[[1.341505, 103.682498],[1.342751, 103.679604],[1.341505, 10…

【微信小程序】自定义组件布局会议OA其他页面(附源码)

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《微信小程序开发实战》。&#x1f3af;&#x1f3a…

如何为 Elasticsearch 创建自定义连接器

了解如何为 Elasticsearch 创建自定义连接器以简化数据摄取过程。 作者&#xff1a;JEDR BLASZYK Elasticsearch 拥有一个摄取工具库&#xff0c;可以从多个来源获取数据。 但是&#xff0c;有时你的数据源可能与 Elastic 现有的提取工具不兼容。 在这种情况下&#xff0c;你可…

推荐 3 个国外的自由职业者/兼职网站,大家有空可以去淘淘金

推荐 3 个国外的自由职业者/兼职网站&#xff0c;大家有空可以去淘淘金 1. Upwork 这个是全球最大的外包网站之一,很多知名公司都会在这里找外包员工 upwork.com 2. fiverr.com 这个平台也是侧重于技能变现&#xff0c;除了专业的职业技能&#xff0c;还有很多稀奇古怪的…

SpringCloud之Ribbon负载均衡解读

目录 基本介绍 概述 LoadBalanced理解 简单源码解读 1&#xff09;LoadBalancerIntercepor 2&#xff09;LoadBalancerClient 3&#xff09;负载均衡策略IRule 4&#xff09;总结 负载均衡策略 负载均衡策略 自定义负载均衡策略 基本介绍 概述 Ribbon是Netflix发布…

Nginx集群负载均衡配置完整流程

今天&#xff0c;良哥带你来做一个nginx集群的负载均衡配置的完整流程。 一、准备工作 本次搭建的操作系统环境是win11&#xff0c;linux可配置类同。 1&#xff09;首先&#xff0c;下载nginx。 下载地址为&#xff1a;http://nginx.org/en/download.html 良哥下载的是&am…

浅谈余压监控系统在住宅小区的应用方案

【摘要】&#xff1a; 本文分析了火灾发生时人员伤亡的主要原因——烟雾&#xff0c;并针对该原因提供切实可靠的系统应用解决方案&#xff0c;并通过具体案例&#xff0c;从设计依据、产品选型、系统组网、现场安装等方式介绍余压监控系统&#xff0c;希望可以在火灾发生时较大…

如何使用前端绘图库(D3.js、Chart.js等)?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

紫光同创FPGA实现PCIE测速试验,提供PDS工程和Linux QT上位机源码和技术支持

目录 1、前言免责声明 2、我这里已有的 GT 高速接口解决方案3、设计思路框架PCIE硬件设计PCIE IP核添加和配置驱动文件和驱动安装QT上位机和源码 4、PDS工程详解5、上板调试验证并演示6、福利&#xff1a;工程代码的获取 紫光同创FPGA实现PCIE测速试验&#xff0c;提供PDS工程和…

spring 提前编译:AOT

文章目录 AOT概述GraalvmNative Image演示Native Image构建过程GraalVM安装&#xff08;1&#xff09;下载GraalVM 安装C的编译环境 Native Image构建 AOT概述 JIT与AOT的区别 JIT和AOT 这个名词是指两种不同的编译方式&#xff0c;这两种编译方式的主要区别在于是否在“运行时…

vue源码笔记之——响应系统

vue是一种声明式范式编程&#xff0c;使用vue者只需要告诉其想要什么结果&#xff0c;无需关心具体实现&#xff08;vue内部做了&#xff0c;底层是利用命令式范式&#xff09; 1. reactive为什么只能操作对象&#xff0c;对于基本数据类型&#xff0c;需要用ref&#xff1f; …

Nginx 代理

目录 正向代理 反向代理 负载均衡 负载均衡的工作原理 优势和好处 算法和策略 应用领域 Nginx 的反向代理 应用场景 在网络通信中&#xff0c;代理服务器扮演着重要的角色&#xff0c;其中正向代理和反向代理是两种常见的代理服务器模式。它们在网络安全、性能优化和…

vue3后台管理系统之pinia及持久化集成使用

安装依赖 pnpm i pinia 在src目录下创建store 创建大仓库 //仓库大仓库 import { createPinia } from pinia //创建大仓库 const pinia createPinia() //对外暴露&#xff1a;入口文件需要安装仓库 export default pinia 全局注册pinia 配置用户仓库pinia管理数据 // 创建用…

JavaSE入门---认识Java数组

文章目录 一. 数组的基本概念1.1 为什么要使用数组&#xff1f;1.2 什么是数组&#xff1f;1.3 数组的使用 二. 数组是引用类型三. 数组的应用场景四. 数组中的常用方法五. 二维数组 一. 数组的基本概念 1.1 为什么要使用数组&#xff1f; 想象这样的一个场景&#xff1a;期末…

混淆技术研究笔记(七)Ant扩展介绍

ant 扩展官方文档&#xff1a;https://ant.apache.org/manual/develop.html Writing Your Own Task 编写你自己的任务 1. 创建一个XXTask类 创建一个Java类继承org.apache.tools.ant.Task &#xff0c;实际上不继承也可以&#xff0c;定义一个 execute() 方法就可以&#xf…

【python】制作一个windows端自动化工具!

作为一名自动化工程师&#xff0c;这一章&#xff0c;带大家来看看我是如何制作一个windows端的自动化工具&#xff0c;本章节内容我会从基础的环境配置、基础模块介绍、框架设计、实际运用等方面来讲解&#xff0c;对于想要未来从事该行业的人来说&#xff0c;希望这篇文章能给…

公司重要文件防泄密

公司重要文件防泄密是企业管理中一项非常重要的任务&#xff0c;今天分享几个可以防止公司重要文件泄密的方式&#xff1a; 1、建立完善的文件管理制度 企业应该制定严格的文件管理制度&#xff0c;包括文件分类、加密、访问权限的管理等。确保每个员工都了解文件管理制度并严…

【力扣1528】重新排列字符串

&#x1f451;专栏内容&#xff1a;力扣刷题⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录 一、题目描述二、题目分析1、Java代码2、C代码 一、题目描述 给你一个字符串 s 和一个长度相同的整数数组 indices。 请你…