leetcode189 轮转数组


1.前言

写博客监督自己,至少保证每天一条,解法不一定全,也不一定是最好的,仅供参考。


2.解法

2.1 中间数组

最简单的想法就是新建一个数组,然后复制

System.arraycopy(int[] arr, int star,int[] arr2, int start2, length);
//				被复制数组	开始下标	目标数组	开始放入位置		复制个数
//写的第一个版本,测试用例 [-1] k=2 报错,nums.length=1,1-2=-1 导致数组索引越界
class Solution {
    public void rotate(int[] nums, int k) {
        //添加后通过测试
        if(k > nums.length){
            k = k % nums.length;
        }
        
        int[] newArr = new int[nums.length];
        System.arraycopy(nums, 0, newArr, 0, nums.length);
        System.arraycopy(newArr, nums.length - k, nums, 0, k);
        System.arraycopy(newArr, 0, nums, k, nums.length - k);
    }
}

或者

class Solution {
    public void rotate(int[] nums, int k) {
        if(k > nums.length){
            k = k % nums.length;
        }
        int[] newArr = new int[nums.length];
        for(int i = 0; i < k; i++){
            newArr[i] = nums[nums.length - k + i];
        }
        for(int i = k; i < nums.length; i++){
            newArr[i] = nums[i - k];
        }

        System.arraycopy(newArr, 0, nums, 0, nums.length);
    }
}

时间复杂度O(n)

空间复杂度O(n)


2.2 冒泡轮转

每次向右轮转的过程中,类似冒泡排序

输入: nums = [1,2,3,4], k = 1
向右轮转 1 步: [1,2,3,4]——》[1,2,4,3]-》[1,4,2,3]-》[4,1,2,3]
class Solution {
    public void rotate(int[] nums, int k) {
        for(int i = 0; i < k; i++){
            for(int j = nums.length - 1; j > 0; j--){
                int temp = nums[j];
                nums[j] = nums[j - 1];
                nums[j - 1] = temp;
            }
        }
    }
}

时间复杂度O(n*k)

空间复杂度O(1)

提交时,有一个测试用例为new int[100000],k=54944时,运行超时


2.3 分块反转

举例:1,2,3,4,5,6 k=2

  1. 分成两部分1234和56
  2. 轮转1234——》4321 变成432156
  3. 轮转56——》65 变成432165
  4. 轮转整个数组 变成561234
class Solution {
    public void rotate(int[] nums, int k) {
        if(k > nums.length){
            k = k % nums.length;
        }
        int l = nums.length - k;
        reverse(nums, 0, l - 1);
        reverse(nums, l, nums.length - 1);
        reverse(nums, 0, nums.length - 1);
    }

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

时间复杂度O(n)

空间复杂度O(1)


3.原题

给定一个整数数组 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 < = n u m s . l e n g t h < = 1 0 5 1 <= nums.length <= 10^5 1<=nums.length<=105
  • − 2 31 < = n u m s [ i ] < = 2 31 − 1 -2^{31} <= nums[i] <= 2^{31} - 1 231<=nums[i]<=2311
  • 0 < = k < = 1 0 5 0 <= k <= 10^5 0<=k<=105

进阶:

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

  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述:给定一个非负整数数组nums和一个整数m,你需要将这个数组分成m个非空的连续子数组。设计一个算法使得这m个子数组中的最大和最小。 解题思路: 这是一个典型的二分搜索题目,可以使用二分查找来解决。 1. 首先确定二分的左右边界。左边界为数组中最大的值,右边界为数组中所有元素之和。 2. 在二分搜索的过程中,计算出分割数组的组数count,需要使用当前的中间值来进行判断。若当前的中间值不够分割成m个子数组,则说明mid值偏小,将左边界更新为mid+1;否则,说明mid值偏大,将右边界更新为mid。 3. 当左边界小于等于右边界时,循环终止,此时的左边界即为所求的结果。 具体步骤: 1. 遍历数组,找到数组中的最大值,并计算数组的总和。 2. 利用二分查找搜索左右边界,从左边界到右边界中间的值为mid。 3. 判断当前的mid值是否满足题目要求,若满足则更新右边界为mid-1; 4. 否则,更新左边界为mid+1。 5. 当左边界大于右边界时,循环终止,返回左边界即为所求的结果。 代码实现: ```python class Solution: def splitArray(self, nums: List[int], m: int) -> int: left = max(nums) right = sum(nums) while left <= right: mid = (left + right) // 2 count = 1 total = 0 for num in nums: total += num if total > mid: total = num count += 1 if count > m: left = mid + 1 else: right = mid - 1 return left ``` 时间复杂度分析:二分搜索的时间复杂度为O(logN),其中N为数组的总和,而遍历数组的时间复杂度为O(N),因此总的时间复杂度为O(NlogN)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值