给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
说明:
- 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
- 要求使用空间复杂度为 O(1) 的 原地 算法。
最一开始想到的是
for _ in 0..<k {
nums.insert(nums.last ?? 0, at: 0)
nums.removeLast()
}
结果提示
只打败了23%的用户,说明优化空间很大
之后继续尝试, 经过朋友的提示,仔细阅读题目想到
//这里取余是为了应对k>nums.count的情况
let k = k % nums.count
nums = nums.suffix(k) + nums.prefix(nums.count-k)
结果
时间快了,内存使用却上去了,还是想要继续优化,于是想到把两个方法结合下。
let k = k % nums.count
nums.insert(contentsOf: nums.suffix(k), at: 0)
nums.removeLast(k)
最后结果自然失败的,没有任何进步
思来想去,找不到更好的答案找到去看了官方的解答,他们用了 环形替换 很巧妙的方法,我看到之后只觉得,人家的才叫算法,自己写的那就大力出奇迹(我看了半天才看懂)。翻译成swift如下
var count = 0
var start = 0
while count < nums.count {
var current = start
var prev = nums[start]
repeat {
let next = (current+k) % nums.count
let temp = nums[next]
nums[next] = prev
prev = temp
current = next
count += 1
} while (start != current)
start += 1
}
他的算法,无论是时间还是空间都做到了十分优秀
总结一下:
1、第一种算法最暴力最简单,甚至连替换都没有,就是插入,删除。
- 时间复杂度:O(n∗k)
- 空间复杂度:大于O(1)
如果他做了替换,空间复杂度应该是O(1)
2、有了进步,使用了swift的语法糖
他的复杂度实无法评估,之后会尽量少使用swift自带的语法,用最基础的语法去实现。
3、最后尝试了环形替换 很复杂,但好像在速度上没有比第二种方法有太多的进步,但是在内存使用上确实有了很大的进步。
- 时间复杂度:O(n)
- 空间复杂度:O(1)