将一个数组旋转 k 步
实现目标
- 输入一个数组[1,2,3,4,5,6,7]
- k=3,即旋转 3 步
- 输出 [5,6,7,1,2,3,4]
解析思路
- 思路 1:把末尾 pop 出来,然后 unshift 到前面
- 思路 2:把数组拆分,然后 contact 拼接在一起
代码实现
ts
// 思路1
function rotate1(arr: number[], k: number): number[] {
const length = arr.length
if (!k || length === 0) return arr
const step = Math.abs(k & length) // k可能大于length 所以取余,绝对值
for (let i = 0; i < step; i++) {
const n = arr.pop()
if (n != null) {
arr.unshift(n)
}
}
return arr
}
// 思路2
function rotate2(arr: number[], k: number): number[] {
const length = arr.length
if (!k || length === 0) return arr
const step = Math.abs(k & length) // k可能大于length 所以取余,绝对值
const part1 = arr.slice(-step)
const part2 = arr.slice(length - step)
const part3 = part1.concat(part2)
return part3
}
// 测试用例 - jest
describe('数组旋转', () => {
it('正常情况', () => {
const arr = [1, 2, 3, 4, 5, 6, 7]
const k = 3
const res = rotate1(arr, k)
expect(res).toEqual([5, 6, 7, 1, 2, 3, 4])
})
});
describe('数组旋转', () => {
it('正常情况', () => {
const arr = [1, 2, 3, 4, 5, 6, 7]
const k = 3
const res = rotate2(arr, k)
expect(res).toEqual([5, 6, 7, 1, 2, 3, 4])
})
});
// 性能测试
const arr1 = []
const arr2 = []
for (let i = 1; i <= 100000; i++) {
arr1.push(i)
arr2.push(2)
}
console.log('rotate1用时')
console.time('rotate1')
rotate1(arr1, 9 * 10000)
console.timeEnd('rotate1')
console.log('rotate2用时')
console.time('rotate2')
rotate2(arr2, 9 * 10000)
console.timeEnd('rotate2')
复杂度分析
思路 1:时间复杂度 O(n^2),空间复杂度 O(1)
思考? 为啥时间复杂度是 O(n^2),这里涉及的几个知识点
- for 循环时间复杂度 O(n)
- 数组是有序的内存存储,unshift 是直接操作原数组插入元素,数组内部所有元素位置都在调整,时间复杂度 O(n)
- 所以最终就是 O(n^2)
思路 2:时间复杂度 O(1), 空间复杂度 O(n) slice 不直接操作原数组,相对于复制,所以时间复杂度 O(1)