引言

在自己刚刚毕业不久的时候,去了一家公司面试,面试官现场考了我这道题,我记忆深刻,当时没有想到思路,毫无疑问被面试官当成菜鸟了。
最近刚好在研究数组的各种算法实现,就想到这道题,可以拿来实现一下,纪念自己逝去的青春。

需求

假设有这样一个数组

[1,2,3,4,5]

现在想要左移或者右移N位,比如移动1位

//左移1位
[2,3,4,5,1] //右移1位
[5,1,2,3,4]

算法实现

这样一道题目,你先不要看我下面的代码,自己思考一下如何实现它,不管是复杂的还是简单的方法。
可以先告诉你我用了2行代码实现左、右移动元素。

拆分法

当我们没有具体思路的时候,就先假设数组移动1位的情况。

[1,2,3,4,5]
=>
[null,1,2,3,4] and [5,null,null,null,null]
=>
[5,1,2,3,4]

这里可以看成2个数组,一个是没有到达边界的元素移动[null,1,2,3,4],一个是到达了边界的元素移动[5,null,null,null,null],当元素到达边界,就会往数组的初始位置移动,形成了一个循环的过程。

很明显,如果我们将这2个移动后的数组合并起来,就是需求的结果。

移动2位

同样符合2个移动后的数组合并起来为结果的情况

[1,2,3,4,5]
=>
[null,null,1,2,3] and [4,5,null,null,null]
=>
[4,5,1,2,3]

刚好移动数组长度

[1,2,3,4,5]
=>
[1,2,3,4,5] and [] //如果没有,就假设为空数组

合并数组

假设移动1位的情况
上面的步骤,我们找到了规律,接下来要做的是找到2个数组,需要用到slice截取数组元素。
截取第一个数组

arr.slice(0,-1)
// [1,2,3,4]

截取第二个数组

arr.slice(-1)
// [5]

合并数组

arr.slice(-1).concat(arr.slice(0,-1))
// [5,1,2,3,4]

这样你就实现了移动1位的情况,接着,你继续拿+5和-5范围内的数字进行测试,发现都可以正常移动,当数字大于5或者小于-5的时候,代码就无效了,始终输出[1,2,3,4,5]

arr.slice(-6).concat(arr.slice(0,-6))
// [1,2,3,4,5]

我们再加上一个小技巧,求余数,假设是移动6,那么,实际上和移动1是相同的,我们就可以根据公式求余数

n = n%arr.length
// n = 6%5 余1

同理,当移动-6时

n = n%arr.length
// n = -6%5 余-1

接着带入公式,发现输出全部都正确了!!

思路分析完了,应该很清晰了吧,源码在下面、

算法源码

arr表示原始数组,n表示移动的距离,可以是正数、可以是0、也可以是负数、正数表示右移,负数表示左移,0表示不移动。

function moveElement(arr, n) {
if(Math.abs(n)>arr.length) n = n%arr.length
return arr.slice(-n).concat(arr.slice(0,-n))
} // moveElement(arr, 9)
// moveElement(arr, 0)
// moveElement(arr, -9)

总结

下次面试要是继续碰到这道题,可能我又当场忘记思路了?

补充

看到有评论讨论不同方案的实现,这些都很厉害,没有唯一的答案,而思考解决方案的时候,要考虑的是时间复杂度,移动数组的元素都会造成数组的重新排列。

第一步方案我觉得应该是找到最小移动位置的代价,即移动2和移动2n是一样的,我们就只需要移动2,不需要再移动n,求余数的作用在于此,根据移动的位置切分出2个数组,不需要移动元素,最后我用的是concat合并2个数组,返回一个新的数组副本,这样就避免了移动元素。

还有一种方案是将2个数组使用new Set(array1)和new Set(array2)设置为集合,集合是key、value的散列表,可以用最少的代价移动位置,不导致重排,用集合移动完之后,再Array.from()转换回数组。

切忌,不要尝试去直接修改原数组的元素位置,这样做代价非常大,尤其是数组长度很长的时候!!

原文地址:https://segmentfault.com/a/1190000012882330

JavaScript系列——数组元素左右移动N位算法实现的更多相关文章

  1. javascript删除数组元素的7个方法

    在JavaScript中,除了Object之外,Array类型(数组)恐怕就是最常用的类型了.与其他语言的数组相比,JavaScript中的Array非常灵活.这种灵活性有利有弊,好处是其富有创造性, ...

  2. JavaScript中数组元素删除的七大方法汇总

    原文链接:https://blog.csdn.net/u010323023/article/details/52700770 在JavaScript中,除了Object之外,Array类型恐怕就是最常 ...

  3. JavaScript 交换数组元素位置的几种方式

    前言 交换数组元素位置是开发项目中经常用到的场景,总结下用过的几种方式. 第三方变量 最基础的方式,创建一个变量作为中转. let temp = array[index1]; array[index1 ...

  4. javascript中数组元素删除方法splice,用在for循环中巨坑

    一.demo splice: 该方法会改变自动原始数组长度 实例: var array = ["aa","dd","cc","aa ...

  5. 使用JavaScript进行数组去重——一种高效的算法

    最近比较忙,没时间更新博客,等忙完这阵子会整理一篇使用AngularJS构建一个中型的单页面应用(SPA)的文章,尽情期待!先占个坑. 数组去重的算法有很多种,以下是一种. 思路如下: 定义一个空的对 ...

  6. Javascript系列——对象元素的数组去重实现

    概要 这是一篇记录文,记录数组操作对象去重的实现. 需求 有这样一个数组 [{ _id: 123, name: '张三' },{ _id: 124, name: '李四' },{ _id: 123, ...

  7. JavaScript的数组系列

    数组 今天逆战班的学习主题关于Javascript的数组,主要有数组的概念.创建.分类.方法.遍历.经典算法...... 一.数组是什么呢?怎么写数组呢?数组有多少种呢? 数组的概念 对象是属性的无序 ...

  8. JavaScript从数组中删除指定值元素的方法

    本文实例讲述了JavaScript从数组中删除指定值元素的方法.分享给大家供大家参考.具体分析如下: 下面的代码使用了两种方式删除数组的元素,第一种定义一个单独的函数,第二种为Array对象定义了一个 ...

  9. JavaScript 数组 length 属性获取数组长度或设置数组元素的数目

    JavaScript 数组 length 属性 JavaScript 数组 length 属性可返回或设置或组中元素的数目,语法如下: array_object.length 利用 length 属性 ...

随机推荐

  1. 移动端和pc端的判断,不同端做不同的处理

    1.通过js判段是pc端还是移动端 function browserRedirect() { var type = ""; var sUserAgent = navigator.u ...

  2. PHP SOAP如何传入复杂对象

    Paymentexpress有一个SOAP服务方法Check3dsEnrollment(String username,String password, EnrolmentCheckRequest t ...

  3. Spark机器学习之MLlib整理分析

    友情提示: 本文档根据林大贵的<Python+Spark 2.0 + Hadoop机器学习与大数据实战>整理得到,代码均为书中提供的源码(python 2.X版本). 本文的可以利用pan ...

  4. 【【henuacm2016级暑期训练】动态规划专题 O】Robot Rapping Results Report

    [链接] 我是链接,点我呀:) [题意] 让你确定一个最小的k 使得1..k这些比赛的结果能够推导出所有人之间的实力大小 [题解] 如果关系越多.那么就越能确定所有人之间的大小关系. (多一点也能唯一 ...

  5. nginx 查看每秒有多少访问量

    nginx访问量统计 1.根据访问IP统计UV awk '{print $1}' access.log|sort | uniq -c |wc -l 2.统计访问URL统计PV awk '{print ...

  6. WCF与WEB API区别

  7. OpenCV基础篇之读取显示图片

    程序及分析 /* * FileName : read.cpp * Author : xiahouzuoxin @163.com * Version : v1.0 * Date : Tue 13 May ...

  8. Java虚拟机的类载入机制

    Java虚拟机类载入过程是把Class类文件载入到内存.并对Class文件里的数据进行校验.转换解析和初始化,终于形成能够被虚拟机直接使用的java类型的过程. 在载入阶段,java虚拟机须要完毕下面 ...

  9. hdoj--4857--逃生(拓扑排序+反向建图)

    逃生 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submiss ...

  10. BZOJ 2179 FFT模板

    思路:FFT板子题 //By SiriusRen #include <cstdio> #include <complex> using namespace std; typed ...