LeetCode面试150——189轮转数组

news2024/9/22 1:08:05

题目难度:中等

默认优化目标:最小化平均时间复杂度。

Python默认为Python3。

目录

1 题目描述

2 题目解析

3 算法原理及程序实现

3.1 暴力求解

3.2 循环链表

3.3 环状替代

3.4 数组翻转

4 题目难度

参考文献


1 题目描述

给定一个整数数组 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)原地 算法解决这个问题吗?

2 题目解析

输入是一个整数数组nums,输出是元素向右轮转k个位置后的数组。

暴力求解就是另外开辟一个数组,把nums中的元素按照题目要求一个一个放进去。这显然去面试的人每个人应该都会,所以不推荐,没优势。另外一种就是循环指针,把数组的首尾连接起来,依次向右轮转。

3 算法原理及程序实现

3.1 暴力求解

我们新开辟一个数组temp,然后遍历nums,将nums中的元素轮转k个位置取出放入temp,最后再用temp更新nums

平均时间复杂度O(n),平均空间复杂度O(n)。

C++代码实现

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int n=nums.size();
        vector<int> temp(n);
​
        for(int i=0;i<n;i++){
            temp[(i+k)%n]=nums[i];//轮转
        }
        nums.assign(temp.begin(),temp.end());//将temp中的元素全部复制到nums
​
    }
};

Python代码实现

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        n = len(nums)
        temp = [0] * n
​
        for i in range(n):
            temp[(i + k) % n] = nums[i]
        
        nums[:] = temp
​
​

3.2 循环链表

我们将数组nums首尾相连,用一个指针指向原来尾的位置,向左移动k个位置后断开,就产生了新的头尾。这样新的数组就是所求的数组。但毕竟这是数组不是链表,没这么方便。将数组转换成列表,费时又费空间。

平均时间复杂度O(n),平均空间复杂度O(n)。

C++代码实现

class Solution {
public:
    struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
    };
    
    void rotate(std::vector<int>& nums, int k) {
        if (nums.empty() || k == 0) return;
​
        // 将数组转换为链表
        ListNode* head = new ListNode(nums[0]);
        ListNode* current = head;
        for (int i = 1; i < nums.size(); ++i) {
            current->next = new ListNode(nums[i]);
            current = current->next;
        }
​
        // 找到链表的尾部并连接成环
        ListNode* tail = current;
        tail->next = head;
​
        // 找到新的尾部和头部
        int stepsToNewHead = nums.size() - k % nums.size();
        ListNode* newTail = tail;
        for (int i = 0; i < stepsToNewHead; ++i) {
            newTail = newTail->next;
        }
        ListNode* newHead = newTail->next;
​
        // 断开环
        newTail->next = nullptr;
​
        // 将链表转换回数组
        current = newHead;
        for (int i = 0; i < nums.size(); ++i) {
            nums[i] = current->val;
            current = current->next;
        }
​
        // 释放链表内存
        while (newHead) {
            ListNode* temp = newHead;
            newHead = newHead->next;
            delete temp;
        }
    }
};

Python3代码实现

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
​
class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        if not nums or k == 0:
            return
​
        # 将数组转换为链表
        head = ListNode(nums[0])
        current = head
        for num in nums[1:]:
            current.next = ListNode(num)
            current = current.next
​
        # 找到链表的尾部并连接成环
        tail = current
        tail.next = head
​
        # 找到新的尾部和头部
        steps_to_new_head = len(nums) - k % len(nums)
        new_tail = tail
        for _ in range(steps_to_new_head):
            new_tail = new_tail.next
        new_head = new_tail.next
​
        # 断开环
        new_tail.next = None
​
        # 将链表转换回数组
        current = new_head
        for i in range(len(nums)):
            nums[i] = current.val
            current = current.next
 

3.3 环状替代

要想空间复杂度为O(1),我们不能使用额外的数组,也就是我们只能用一个零时变量temp来保存要被替代的元素。

替换规则为(i+k)%nnnums的长度。要保证每个元素都被替换,我们就要解决循环终止条件。假设我们走了a圈,遍历了b个元素,则有an=bk。an一定是n、k的公倍数。我们希望a越小越好,故an是n、k的最小公倍数lcm(n,k)。所以b=lcm(n,k)/k。所以我们需要遍历的次数为


\frac{n}{lcm(nk)/k}=\frac{nk}{lcm(n,k)}=gcd(n,k)
 

gcd为最大公约数。

平均时间复杂度为O(n),平均空间复杂度为O(1)。

C++代码实现

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int n = nums.size();
        k = k % n;//防止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;
                swap(nums[next], prev);
                current = next;
            } while (start != current);
        }
    }
};
 

Python代码实现

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        n = len(nums)
        k = k % n  # 防止k超过n
        count = gcd(k, n)  # 确定循环次数
        for start in range(count):
            current = start
            prev = nums[start]  # 记录当前元素
            while True:  # 交换操作
                next_idx = (current + k) % n
                nums[next_idx], prev = prev, nums[next_idx]
                current = next_idx
                if start == current:
                    break
 

3.4 数组翻转

该方法的原理:数组中的元素全部向右移动k位置,尾部k%n个元素会移到数组头部,其余元素会向后移动k%n个位置。

该方法步骤:①先将所有元素翻转②翻转[0,k%(n-1)]区间内的元素③翻转[k%n,n-1]区间内的元素。

第一步让尾部元素到头部,第二部让新的头部元素顺序正确,第三步让新的尾部元素顺序正确。

示例如下,n=7,k=3。

操作结果
nums[1,2,3,4,5,6,7]
步骤①[7,6,5,4,3,2,1]
步骤②[5,6,7,4,3,2,1]
步骤③[5,6,7,1,2,3,4]

平均时间复杂度为O(n),平均空间复杂度为O(1)。

C++代码实现

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int n=nums.size();
​
        k%=n;
        reverse(nums.begin(),nums.end());
        reverse(nums.begin(),nums.begin()+k);
        reverse(nums.begin()+k%n,nums.end());        
​
    }
};

Python代码实现

class Solution:
    def rotate(self, nums, k):
        n = len(nums)
        k %= n
        nums.reverse()
        nums[:k] = reversed(nums[:k])
        nums[k:] = reversed(nums[k:])

4 题目难度

这道题难在用O(1)的空间复杂度完成。相比于环状替代,数组翻转方法既好理解效果又好。

参考文献

力扣面试经典150题

力扣官方题解

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

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

相关文章

运维.Linux.bash学习笔记.数组及其使用

运维专题 Bash Shell数组及其使用 此笔记当前仍在修改和编写。 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:http…

基于N32L406+Freertos+letter_shell终端开源库移植

移植教程 这里首先感谢作者的开源 https://gitee.com/zhang-ge/letter-shell) [Letter shell 3.0 全新出发 | Letter (nevermindzzt.github.io)](https://nevermindzzt.github.io/2020/01/19/Letter shell 3.0全新出发/) 1.复制代码 将litter_shell文件夹中的所有文件复制到…

本地使用Git同步、配合Gitee同步至仓库并下拉到本地(亲手调试,全能跑通)

这几天在公司&#xff0c;同事都在使用Gitee上传项目&#xff0c;进行同步&#xff0c;我也进行了简单学习了解了一下版本控制软件Git&#xff0c;挺不错的&#xff0c;故写个笔记记录一下。 本篇博文主要涉及的内容&#xff1a; 1&#xff0c;本地写代码&#xff0c;通过Git同…

软件测试_接口测试面试题

接口测试是软件测试中的重要环节&#xff0c;它主要验证系统不同模块之间的通信和数据交互是否正常。在软件开发过程中&#xff0c;各个模块之间的接口是实现功能的关键要素&#xff0c;因此对接口进行全面而准确的测试是确保系统稳定性和可靠性的关键步骤。 接口测试的核心目…

树上dp学习总结2

今天也是侥幸刷了两道树上dp的问题&#xff0c;第一个还算简单&#xff0c;但是第二个真的可以说是我碰到的蓝题之首&#xff0c;做了一个晚上我只能留下了不争气的口水&#xff08;太饿了&#xff0c;该吃夜宵了&#xff09; P1131 [ZJOI2007] 时态同步 思路&#xff1a;一开…

RK3568笔记四十九:W25Q64驱动开发(硬件SPI1)

若该文为原创文章&#xff0c;转载请注明原文出处。 一、SPI介绍 串行外设接口 (Serial Peripheral interface) 简称 SPI&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线&#xff0c;并 且在芯片的管脚上只占用四根线&#xff0c;节约了芯片的管脚。 …

Word如何设置表格内容的中文和英文字体

1、选中需要设置的表格内容。 2、CtrlD&#xff0c;分别设置中文和英文字体&#xff0c;点确定即可。 提升自己最好的方法就是改变坏习惯&#xff0c;改变坏习惯最好的方法找习惯替代它。坏习惯不改&#xff0c;你永远受到限制&#xff0c;只能原地踏步。To do list&#xf…

爬取指定的天气网站数据

目 录 一、引言 &#xff08;一&#xff09;项目背景 &#xff08;二&#xff09;目标与意义 二、数据获取与处理 &#xff08;一&#xff09;使用的库和模块 &#xff08;二&#xff09;获取天气信息的函数 &#xff08;三&#xff09;数据预处理 三、数据分析…

python np.max怎么用

python np.max的用法&#xff1a; 语法&#xff1a;np.max&#xff1a;(a, axisNone, outNone, keepdimsFalse) 求序列的最值&#xff1b; 最少接收一个参数&#xff1b; axis&#xff1a;默认为列向&#xff08;也即 axis0&#xff09;&#xff0c;axis 1 时为行方向的最…

SQL labs-SQL注入(七,sqlmap对于post传参方式的注入,2)

本文仅作为学习参考使用&#xff0c;本文作者对任何使用本文进行渗透攻击破坏不负任何责任。参考&#xff1a;SQL注入之Header注入_sqlmap header注入-CSDN博客 序言&#xff1a; 本文主要讲解基于SQL labs靶场&#xff0c;sqlmap工具进行的post传参方式的SQL注入&#xff0c…

如何利用大语言模型进行半监督医学图像分割?这篇文章给出了答案

PS&#xff1a;写在前面&#xff0c;近期感谢很多小伙伴关注到我写的论文解读&#xff0c;我也会持续更新吖~同时希望大家多多支持本人的公主号~ 想了解更多医学图像论文资料请移步公主&#x1f478;号哦~~~后期将持续更新&#xff01;&#xff01; 关注我&#xff0c;让我们一…

大模型时代,编程已成为当代大中专学生的必备技能,如何选择编程语言的一些建议

目录 一、具体建议 1. 确定学习目标 &#xff08;1&#xff09;兴趣驱动 &#xff08;2&#xff09;职业规划 2. 评估市场需求 &#xff08;1&#xff09;行业趋势 &#xff08;2&#xff09;就业前景 3. 考虑应用领域 4. 学习资源 &#xff08;1&#xff09;查看官方文档…

idea 常用的快捷键大全 建议收藏!!

IDEA 一款非常优秀的开发工具&#xff0c;本篇博客总结一些在 IDEA 中常用的快捷键&#xff0c;旨在提高开发效率。点击File --> Settings --> keymap便可进入看到 IDEA 提供的快捷键&#xff0c;我们也可以搜索和自定义所有快捷键。下面给出的是IDEA常用操作归纳。 1、…

RK3568平台(触摸篇)串口触摸屏

一.什么是串口屏 串口屏&#xff0c;可组态方式二次开发的智能串口控制显示屏&#xff0c;是指带有串口通信的TFT彩色液晶屏显示控制模组。利用显示屏显示相关数据&#xff0c;通过触摸屏、按键、鼠标等输入单元写入参数或者输入操作指令&#xff0c;进而实现用户与机器进行信…

AI问答:理解CRLF和LF / 两者区别 / 在编程和文件处理中的影响

一、背景 vscode这里的CRLF&#xff0c;点击后有CRLF和LF的两个选项&#xff0c;本文我们理解CRLF 和 LF 二、理解CRLF和LF 2.1、CRLF&#xff1a;起源于早期的打字机和电传打字机&#xff0c;这些设备在打印完一行后&#xff0c;需要先将打印头移回到行首&#xff08;回车&…

【Java题解】杨辉三角—力扣

&#x1f389;欢迎大家收看&#xff0c;请多多支持&#x1f339; &#x1f970;关注小哇&#xff0c;和我一起成长&#x1f680;个人主页&#x1f680; ⭐目前主更 专栏Java ⭐数据结构 ⭐已更专栏有C语言、计算机网络⭐ 题目链接&#xff1a;杨辉三角 目录&#x1f451; ⭐题…

用60行python代码制作一个扫雷

扫雷游戏&#xff08;Minesweeper&#xff09;是一个经典的逻辑游戏&#xff0c;玩家需要在一个包含隐藏地雷的网格中标记出所有地雷的位置&#xff0c;同时避免触发它们。下面&#xff0c;我将提供一个简单的Python扫雷游戏实现&#xff0c;并附带详细的教程。 第一步&#x…

基于cubeMX的STM32的RTC实时时钟实现

1、在仪器仪表的项目开发中&#xff0c;时常需要设备显示当前的日期和时间&#xff0c;这时&#xff0c;可以使用STM32自带的RTC实时时钟模块来实现此功能。这里我们使用STM32F103RCT6单片机芯片为例。 2、cubeMX的设置 &#xff08;1&#xff09;RTC设置 &#xff08;2&…

第十六天内容

上午 静态资源 根据开发者保存在项目资源目录中的路径访问静态资源html 图片 js css 音乐 视频 f12&#xff0c;开发者工具&#xff0c;网络 1、web基本概念 web服务器 &#xff08;web server&#xff09;&#xff1a;也称HTTP服务器&#xff08;HTTP server&…