189. 旋转数组

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> 189. 旋转数组

本题来自 LeetCode:189. 旋转数组[1]

题目描述

给定一个数组,将数组中的元素向右移动  k  个位置,其中  k  是非负数。
示例 1:


输入: [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:


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

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

解法一 向后移动

题目分析

可以采用向后移动的方式解决。
一共需要向后移动 k次,每次将尾节点移到首节点,将位置 [0...n-2]依次移到位置 [1...n-1]

题目解答


class Solution {
    public void rotate(int[] nums, int k) {
        if(nums == null || nums.length == 0) {
            return;
        }
        int n = nums.length;
        k = k % n;
        if(k == 0) {
            return;
        }
        // 向后移动k次,每次将尾节点移到首节点,将位置[0...n-2]依次移到位置[1...n-1]
        for(int i = 0; i  k; i ++) {
            int temp = nums[n - 1];
            for(int j = n - 1; j  0; j --) {
                nums[j] = nums[j - 1];
            }
            nums[0] = temp;
        }
    }
}

复杂度分析:
时间复杂度: O((k % n)* n)
空间复杂度: O(1)

解法二 向前移动

题目分析

也可以采用向前移动的方式解决。
一共需要向前移动 n - k次,每次将首节点移到尾节点,将位置 [1...n-1]依次移到位置 [0...n-2]

题目解答


class Solution {
    public void rotate(int[] nums, int k) {
        if(nums == null || nums.length == 0) {
            return;
        }
        int n = nums.length;
        k = k % n;
        if(k == 0) {
            return;
        }
        // 向前移动n - k次,每次将首节点移到尾节点,将位置[1...n-1]依次移到位置[0...n-2]
        for(int i = 0; i  n - k; i ++) {
            int temp = nums[0];
            for(int j = 0; j  n - 1; j ++) {
                nums[j] = nums[j + 1];
            }
            nums[n - 1] = temp;
        }
    }
}

复杂度分析:
时间复杂度: O((k % n)* n)
空间复杂度: O(1)

解法三

题目分析

为了使元素总的移动次数最少,可以结合前面两种解法来解答。

  • 当`k = n - k`, 向后移动。
  • 当`k n - k`, 向前移动。
  • 题目解答

    
    class Solution {
        public void rotate(int[] nums, int k) {
            if(nums == null || nums.length == 0) {
                return;
            }
            int n = nums.length;
            k = k % n;
            if(k == 0) {
                return;
            }
            if(k  n - k) {
                // 向前移动n - k次,每次将首节点移到尾节点,将位置[1...n-1]依次移到位置[0...n-2]
                for(int i = 0; i  n - k; i ++) {
                    int temp = nums[0];
                    for(int j = 0; j  n - 1; j ++) {
                        nums[j] = nums[j + 1];
                    }
                    nums[n - 1] = temp;
                }
                return;
            }
    
            // 向后移动k次,每次将尾节点移到首节点,将位置[0...n-2]依次移到位置[1...n-1]
            for(int i = 0; i  k; i ++) {
                int temp = nums[n - 1];
                for(int j = n - 1; j  0; j --) {
                    nums[j] = nums[j - 1];
                }
                nums[0] = temp;
            }
        }
    }
    

    复杂度分析:
    时间复杂度: O((k % n)* n)
    空间复杂度: O(1)

    解法四 反转法

    题目分析

    我们也可以分成三步来解决

  • 反转子数组`[0, n -k - 1]`
  • 反转子数组`[n -k, n - 1]`
  • 反转数组`[0, n - 1]`
  • 以示例 1 为例,原数组为 [1,2,3,4,5,6,7] k = 3

    
    1. 反转子数组[0, 3]
    [4, 3, 2, 1, 5, 6, 7]
    2. 反转子数组[4, 6]
    [4, 3, 2, 1, 7, 6, 5]
    3. 反转子数组[0, 6]
    [5, 6, 7, 1, 2, 3, 4]
    

    题目解答

    
    class Solution {
        public void rotate(int[] nums, int k) {
            if(nums == null || nums.length == 0) {
                return;
            }
            int n = nums.length;
            k = k % n;
            if(k == 0) {
                return;
            }
            // 反转子数组[0, n -k - 1]
            reverse(nums, 0, n - k - 1);
            // 反转子数组[n -k, n - 1]
            reverse(nums, n - k, n - 1);
            // 反转数组[0, n - 1]
            reverse(nums, 0, n - 1);
        }
    
        public void reverse(int[] nums ,int begin, int end) {
            while(begin  end) {
                swap(nums, begin ++, end --);
            }
        }
    
        public void swap(int[] nums ,int i, int j) {
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
        }
    }
    

    复杂度分析:
    时间复杂度: O(n)
    空间复杂度: O(1)

    参考资料

    1. 旋转数组: https://leetcode-cn.com/problems/rotate-array

    原文始发于微信公众号(xiaogan的技术博客):

    本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

    本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

    原文链接:blog.ouyangsihai.cn >> 189. 旋转数组


      转载请注明: 好好学java 189. 旋转数组

     上一篇
    61. 旋转链表 61. 旋转链表
    本题来自 LeetCode:61. 旋转链表[1] 题目描述给定一个链表,旋转链表,将链表每个节点向右移动  k  个位置,其中  k  是非负数。示例  1: 输入: 1-2-3-4-5-NULL, k = 2 输出: 4-5-1-2-
    2021-04-05
    下一篇 
    200. 岛屿数量 200. 岛屿数量
    本题来自 LeetCode:200. 岛屿数量[1] 题目描述给定一个由  ‘1’(陆地)和 ‘0’(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包
    2021-04-05