数组循环移位的几种解法

题目描写叙述:
设计一个算法,把一个含有N个元素的数组循环右移K位。

解法一:
最easy想到的就是每次将数组中的元素右移一位,循环K次。

#include<iostream>
using namespace std;
void RightShift(int *arr, int N, int K){
     while(K--){
          int t = arr[N-1];
          for(int i = N-1;i>0;i--){
                arr[i]=arr[i-1];
          }
          arr[0]=t;
    }

 }

int main(){
   int num[4] = {1,3,7,9};
   for(int i = 0; i < 4;i++){
      cout<<num[i]<<' ';
   }
   cout<<'\n';
   RightShift(num,4,2);
   for(int i = 0; i < 4;i++){
      cout<<num[i]<<' ';
   }

这里的复杂度为K*N次,我们接下来再用一个方法来改进。

解法二:
用空间来换时间,申请一个大小为K%N的数组,由于循环移位K次,假设K > N。则其效果与移动K%N次是一样的。

所以在解法一,我们能够加上 K = K %N 这句。
假如原数组: 1 2 3 4 5 6 7 须要右移4次。那么我们想要的结果是: 5 6 7 1 2 3 4
我们注意到。事实上就是将1234前四个元素拿出来(变成array A: _ _ _ _ 5 6 7, array B:1 2 3 4),然后将567前移充填(A 变成 5 6 7 _ _ _ _)。然后我们仅仅要将 B 数组再加入到A 数组后面就完毕了。 最后 (A : 5 6 7 1 2 3 4)

void RightShift(int *arr, int N, int K){
     K = K % N;
     int *sp = (int*)malloc(K*sizeof(int));
     int i = 0,s = 0;
     for(; i < K;i++){        // 将数组前K 位存入sp中
         sp[i] = arr[i];
     }
     for(;i<N;i++,s++){       // 将数组第K+1 - N 位移到arr前端。
        arr[s] = arr[i];
     }
     for(i = 0; s < N;i++,s++){    // 将sp中的数取出,拼入arr数组。
        arr[s] = sp[i];
     }
}

这里对数组进行了复制K次。将后面的元素前移N-K次,然后再将K 个元素拼接到数组后面进行了K次操作。一共进行了N+K次操作。然而空间复杂度为K.

解法三:
这里有一个非常巧妙的方法来实现数组循环。


假如原数组: 1 2 3 4 5 6 7 须要右移4次,那么我们想要的结果是: 5 6 7 1 2 3 4。
1.将1234逆置 变成 4321
2.将567逆置 变成 765
3.将两个逆置数组拼接: 4321765
4.将这个已拼接的数组逆置: 5671234 就成了我们想要的结果了。

void Reverse(int *arr,int start,int end){      //逆置
    for(; start < end;start++,end--){
           int s = arr[end];
           arr[end] = arr[start];
           arr[start] = s;
      }
}

void RightShift(int* arr,int N, int K){
      K = K%N;                       //相应上文步骤
      Reverse(arr,0,K-1);           //1 
      Reverse(arr,K,N-1);           //2
      Reverse(arr,0,N-1);           //4
}

上述算法Reverse函数时间复杂度分别为K/2, (N-K)/2,N/2, 所以总的复杂度为O(N)。空间复杂度为O(1)

转载于:https://www.cnblogs.com/zhchoutai/p/8724172.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最小循环子数组是指在一个循环数组中,找到一个连续子数组,使该子数组的和最小。对于解决这个问题,可以使用Java编程语言来实现。 首先,我们需要定义一个函数来计算数组的和。该函数的输入参数为一个整数数组,返回值为数组的总和。下面是该函数的Java代码实现: ```java public int getSum(int[] nums) { int sum = 0; for (int num : nums) { sum += num; } return sum; } ``` 接下来,我们可以编写一个函数来找到最小循环子数组的和。该函数的输入参数为一个整数数组,返回值为最小循环子数组的和。下面是该函数的Java代码实现: ```java public int findMinSubarraySum(int[] nums) { int sum = getSum(nums); int currentSum = 0; int minSum = sum; for (int i = 0; i < nums.length; i++) { currentSum += nums[i]; if (currentSum > sum) { currentSum = nums[i]; } minSum = Math.min(minSum, currentSum); } return minSum; } ``` 在这段代码中,我们使用了一个变量currentSum来记录当前子数组的和,另一个变量minSum来记录最小循环子数组的和。在遍历数组过程中,如果当前子数组的和大于整个数组的总和,就将currentSum重置为当前元素的值。每次更新minSum时,都使用Math.min函数来比较两个和的大小,并将较小的值赋给minSum。 最后,我们可以调用findMinSubarraySum函数来找到最小循环子数组的和。下面是一个例子: ```java int[] nums = {4, 3, -2, -1, -3, 4, 5}; int minSubarraySum = findMinSubarraySum(nums); System.out.println("最小循环子数组的和为:" + minSubarraySum); ``` 以上就是最小循环子数组问题的Java解法,通过以上的代码实现,可以计算出最小循环子数组的和。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值