php旋转数组,每日一道算法:旋转数组

题目:给定一个数组,将数组中的元素向右移动 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次,每次将数组旋转一个元素(将数组中每个元素和最后一个元素值进行交换)

PHP代码实现:

/**

* @param Integer[] $nums

* @param Integer $k

* @return NULL

*/

function rotate(&$nums, $k) {

for($i=0;$i

$last = $nums[count($nums)-1];

for($j=0;$j

$temp = $nums[$j];

$nums[$j] = $last;

$last = $temp;

}

}

return $nums;

}

使用:

$nums = [1,2,3,4,5,6,7,10];

$k = 3;

var_dump(rotate($nums,$k));

复杂度分析:

时间复杂度: O(k*n)

每个元素都被移动1步:O(n),k次:O(k)

空间复杂度: O(1)

没有额外空间被使用

当数组长度大一点时,很容易超出时间限制,明显是一个很粗暴的解决方法

解法二:反转法

思路分析:

当我们旋转k次后,k%n个尾部元素会移动到数组前头,剩余的元素被往后移动

首先将所有数组反转,接着再把前k个元素反转,最后再反转后n-k个元素

假设 nums = [1,2,3,4,5,6,7] n=7 且 k=3

反转所有元素:[7,6,5,4,3,2,1]

反转前k个元素:[5,6,7,4,3,2,1]

反转后n-k个元素:[5,6,7,1,2,3,4] 此时即为结果

PHP代码实现:

/**

* @param Integer[] $nums

* @param Integer $k

* @return NULL

*/

function rotate(&$nums, $k) {

$k %=count($nums);

$nums = reverse($nums,0,count($nums)-1);

$nums = reverse($nums,0,$k-1);

$nums = reverse($nums,$k,count($nums)-1);

return $nums;

}

/**

* @param $nums

* @param $start

* @param $end

* @return mixed

*/

function reverse($nums,$start,$end){

while($start

$temp = $nums[$start];

$nums[$start] = $nums[$end];

$nums[$end] = $temp;

$start++;

$end--;

}

return $nums;

}

复杂度分析:

时间复杂度: O(n)

n个元素被反转了3次,即3*O(n),还是O(n)

空间复杂度:O(1)

没有额外空间被使用

解法三:环状替换

思路分析:

把数组当成环形的,把每个元素放到其后k个位置

比如[1,2,3,4,5,6,7,8],k=2

可以把这8个元素依次放在一个八边形的各个顶点,从元素为1的顶点开始依次往前移动2个位置,最后的数组[7,8,1,2,3,4,5,6]即为结果

0170217afdb7f7a7b18be95aa26292f6.png

PHP代码实现:

/**

* @param Integer[] $nums

* @param Integer $k

* @return NULL

*/

function rotate(&$nums, $k) {

$k = $k%count($nums);

$count = 0;

for($start=0;$count

$current = $start;//当前位置的指针

$prev = $nums[$start];

do {

$next = ($current+$k)%count($nums);

$temp = $nums[$next];

$nums[$next] = $prev;

$prev = $temp;

$current = $next;

$count++;//控制循环的次数

} while($start != $current);//开始位置和当前位置不同一个位置才进行元素移动

}

return $nums;

}

复杂度分析:

时间复杂度:O(n)

只遍历了每个元素一次

空间复杂度:O(1)

使用了常数个额外空间

解法四:循环遍历(k次)+哈希函数

思路分析:

先截取出前n-k个元素到一个新数组,循环遍历k次(从最后一个元素倒序遍历),把每次循环的指针位置对应的元素插到新数组前边

PHP代码实现:

/**

* @param Integer[] $nums

* @param Integer $k

* @return NULL

*/

function rotate(&$nums, $k) {

$start = count($nums)-$k;

$res = array_slice($nums,0,$start);

for($i=count($nums)-1;$i>=$start;$i--){

array_unshift($res,$nums[$i]);

}

return $res;

}

复杂度分析:

时间复杂度: O(n),其中n为k

只遍历了k次

空间复杂度: O(n)

使用了新数组空间

解法五:哈希函数

思路分析:

先截取出前n-k个元素到一个新数组,再截取后k个元素到另外一个新数组,最后倒序合并这两个数组即可

PHP代码实现:

/**

* @param Integer[] $nums

* @param Integer $k

* @return NULL

*/

function rotate(&$nums, $k) {

$res_start = array_slice($nums,0,count($nums)-$k);

$res_end = array_slice($nums,count($nums)-$k,$k);

return array_merge($res_end,$res_start);

}

复杂度分析:

时间复杂度:O(n)

空间复杂度: O(n)

使用了新数组空间

github

题目来源

本作品采用《CC 协议》,转载必须注明作者和本文链接

阿德

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值