力扣面试经典算法150题:轮转数组

轮转数组

今天的题目是力扣面试经典150题中的数组的基础难度题:轮转数组。

题目链接:https://leetcode.cn/problems/rotate-array/description/?envType=study-plan-v2&envId=top-interview-150

问题描述

给定一个整型数组 nums 和一个整数 k,将数组中的元素向右轮转 k 个位置。

例如,给定数组 [1,2,3,4,5,6,7] 和 k = 3,轮转后的数组应该是 [5,6,7,1,2,3,4]。

  • 示例

    • 输入:
      nums = [1,2,3,4,5,6,7]
      k = 3
    • 输出:
      [5,6,7,1,2,3,4]
  • 示例:

    • 输入:
      nums = [-1,-100,3,99]
      k = 2
    • 输出:
      [3,99,-1,-100]

题目分析

题目要求能够将一个整型数组中的所有元素向右轮转 k 个位置。

先根据题目中的示例,理解一下轮转的含义。

观察示例可以发现,轮转意味着数组的最K个元素会按原有的顺序被移动到数组的最前面,而数组前面的元素则相应地向后移动。

解题思路

题目有多种解题思路,我们一个个来。

复制替换法

这个问题第一时间想到的方法是新建一个数组,将先将目标K个元素放入到新数组中,然后根据轮转的要求将原数组中的元素复制到新数组的正确位置上。最后将新数组的内容复制回原数组。这是方法一,我们叫它复制替换法。

在解答数组题目时,我们通常考虑不使用额外空间,也就是不新建数组的方式,所以我们再思考一下,怎么能在原数组上操作实现轮转。

反转数组法

轮转的意义是将后面K个元素放到前面,前面的元素放到后面,同时保证顺序不变。同时,我们不想操作额外的空间,就在原数组上操作。那么我们是不是可以先将整个数组反转,这个时候是不是相当于前面的元素放到了后面,后面的元素放到了前面,这个时候我们只需要考虑得到是,前k个元素需要按原来的位置摆放,后n-k个元素也按原来的位置摆放就行?

这两部分的元素如何恢复原有的顺序呢?还是反转,正所谓负负得正,我们反转得到的数组,再反转不就回到之前吗?

这样,先反转整体,在分别反转两部分的方法,我们叫它反转数组法,这是第二种方法。

实际算法代码

根据上面分析的两种方法,我们可以编写如下代码:

java 复制代码
public class Solution {


    public static void main(String[] args) {
        Solution solution = new Solution();
        int[] nums = {1, 2, 3, 4, 5, 6, 7};
        int k = 3;
        solution.rotate(nums, k);
        solution.rotate2(nums, k);
        for (int num : nums) {
            System.out.print(num + " ");
        }
    }


    public void rotate(int[] nums, int k) {
        int n = nums.length;
        k %= n; // 防止k大于数组长度的情况
        int[] result = new int[n];

        for (int i = 0; i < n; i++) {
            result[(i + k) % n] = nums[i];
        }
        for (int i = 0; i < n; i++) {
            nums[i] = result[i];
        }
    }


    public void rotate2(int[] nums, int k) {
        int n = nums.length;
        k %= n; // 处理 k 大于数组长度的情况
        reverse(nums, 0, n - 1); // 反转整个数组
        for (int num : nums) {
            System.out.print(num + " ");
        }
        System.out.println();
        reverse(nums, 0, k - 1); // 反转前 k 个元素
        for (int num : nums) {
            System.out.print(num + " ");
        }
        System.out.println();
        reverse(nums, k, n - 1); // 反转剩余的元素
        for (int num : nums) {
            System.out.print(num + " ");
        }
        System.out.println();
    }

    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--;
        }
    }

需要注意,两个函数不能同时调用,因为第一个函数过后,原数组已经被轮转了,第二个函数轮转的第一个轮转以后的数组。

结果

执行函数,测试通过:

图片是使用反转法输出,可以看到原数组被一步步反转成了目标数组。

提交到力扣,也正常通过:

总结

根据我们对函数的分析以及力扣提交后的结果,我们发现:

  1. 复制替换法使用了额外的空间,时间复杂度为 O(n),空间复杂度为 O(n)。这种方法简单易懂,适合初学者理解轮转的概念。
  2. 反转数组法在原地完成轮转操作,时间复杂度为 O(n),空间复杂度为 O(1)。这种方法虽然实现稍微复杂一点,但更节省空间。

力扣中还有最一个循环设置法,我没有想到,看了一下实现。简单的说就是一个个元素循环去放置。

这个方法比较复杂,但是一步步去debug观察元素的移动,可以很大程度上帮助新手理解数组的交换与移动,感兴趣的可以自己实现一下。

加油!!!

相关推荐
魔道不误砍柴功2 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2342 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
pianmian12 小时前
python数据结构基础(7)
数据结构·算法
闲晨2 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
测开小菜鸟3 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
好奇龙猫4 小时前
【学习AI-相关路程-mnist手写数字分类-win-硬件:windows-自我学习AI-实验步骤-全连接神经网络(BPnetwork)-操作流程(3) 】
人工智能·算法
P.H. Infinity4 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天4 小时前
java的threadlocal为何内存泄漏
java
sp_fyf_20244 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01
人工智能·深度学习·神经网络·算法·机器学习·语言模型·数据挖掘
caridle4 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express