力扣面试经典算法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观察元素的移动,可以很大程度上帮助新手理解数组的交换与移动,感兴趣的可以自己实现一下。

加油!!!

相关推荐
yuren_xia8 分钟前
Spring MVC中自定义日期类型格式转换器
java·spring·mvc
m0_5041353012 分钟前
代码随想录算法训练营第六十一天 | floyd算法
算法
GottdesKrieges1 小时前
OceanBase数据库磁盘空间管理
java·数据库·oceanbase
Themberfue2 小时前
Redis ⑦-set | Zset
java·开发语言·数据库·redis·sql·缓存
xin007hoyo4 小时前
算法笔记.染色法判断二分图
数据结构·笔记·算法
程序员曦曦5 小时前
17:00开始面试,17:08就出来了,问的问题有点变态。。。
自动化测试·软件测试·功能测试·程序人生·面试·职场和发展
_一条咸鱼_5 小时前
揭秘 Android View 位移原理:源码级深度剖析
android·面试·android jetpack
_一条咸鱼_5 小时前
深度剖析:Android View 滑动原理大揭秘
android·面试·android jetpack
_一条咸鱼_5 小时前
深度揭秘:Android View 滑动冲突原理全解析
android·面试·android jetpack