小哆啦与数组轮转的冒险

85 阅读2分钟

小哆啦与数组轮转的冒险

小哆啦开始力扣每日一题的第五天

189. 轮转数组 - 力扣(LeetCode)

在一个阳光明媚的早晨,小哆啦猫收到了一位老教授的请求:帮助他将一个数字阵列向右移动 kk 步。老教授说:“这可不是普通的任务,需要既简单又高效的方法!”


小哆啦的第一步尝试:手动轮转

小哆啦思索片刻,决定用最直观的方法解决这个问题。他拿出百宝袋,取出一个“推拉机关”,将数组的最后一个数字取出,然后放到数组的最前面。他开心地说道:

“这样一来,每次移动一步,重复 kk 次,肯定能搞定啦!”

他写下了自己的方法:

function rotate(nums: number[], k: number): void {
    for (let i = 0; i < k; i++) {
        nums.unshift(nums.pop()!);
    }
}

然后小哆啦测试了一下:

const nums = [1, 2, 3, 4, 5, 6, 7];
const k = 3;

rotate(nums, k);
console.log(nums); // 输出:[5, 6, 7, 1, 2, 3, 4]

果然成功了!小哆啦拍了拍手,心满意足。不过,他很快发现了问题:

当数组变得很长,或者 kk 特别大的时候,他需要重复操作很多次,耗时越来越久。教授皱了皱眉:“小哆啦,这方法虽然可爱,但能不能再优化一点?”


优化后的高效方法:反转法

小哆啦拿起放大镜,仔细观察这个问题,突然灵机一动:

“其实我不需要每次移动一步,只要一次性调整位置就可以啦!”

他决定使用“切片法”,将数组分为两部分:

  1. 取出最后 kk 个数字,称为“尾巴”。
  2. 取出前面剩下的部分,称为“头部”。
  3. 重新拼接尾巴和头部,顺序调整后即可完成。

小哆啦开心地记录下这个优化的思路:

function rotate(nums: number[], k: number): void {
    k = k % nums.length; // 防止 k 超过数组长度
    const tailPart = nums.slice(-k); // 最后 k 个元素
    const headPart = nums.slice(0, nums.length - k); // 剩余部分
    nums.splice(0, nums.length, ...tailPart, ...headPart); // 拼接赋值
}

他再次测试:

const nums = [1, 2, 3, 4, 5, 6, 7];
const k = 3;

rotate(nums, k);
console.log(nums); // 输出:[5, 6, 7, 1, 2, 3, 4]

小哆啦的结论

教授看了看两种方法,点了点头:“你的第一种方法虽然直观,但在处理大数组时效率不高。而优化后的切片法,却能一次性完成任务,时间复杂度从 O(k×n)降到了 O(n)。”

小哆啦笑眯眯地说道:

“方法的选择要看场景,效率和直观性其实并不矛盾,只要多动脑筋,就能找到最适合的解决方案!”

从此,小哆啦的聪明才智被更多人知晓,他也更爱解开一个个编程难题,为小镇带来智慧和欢乐!