Missing Number 类,元素交换,数组环形跳转
Missing Number 类,元素交换,数组环形跳转
FB 的超高频,记得先演一演,给个 swap 的写法~
这种写法中,我们调用 swap 的次数取决于从数组第一个 0 开始,后面到底有多少个非 0 元素。
一次 swap = 2次数组写入 + 1次 temp variable 写入,总写入次数为 O(3n),总数组写入次数为 O(2n).
然后 follow-up 肯定是如何减少写入次数 (aka 别用 swap),后面的演技就是这样……
其实我一直觉得这个写法才是最直观的,暴力点用 swap 的写法反而 tricky 一点。。
这种写法中,数组每一个位置一定会被不多不少写入一次,写入次数为 O(n)
等差数列。 英文叫 arithmetic sequence,记一下,和老外面试官吹比用。。
这题挺 tricky 的,到现在也是记的九章的答案。
思路就是不断试图把当前元素替换到其正确的位置上;如果目标位置元素已经正确则 do nothing,如果目标位置越界,也 do nothing. 每次交换之后指针位置不动,继续试图新一轮替换。这样一次循环之后,所有能被放到正确位置的元素,都会被放过去,而第一个位置和值不匹配的元素就是我们要寻找的目标。
注意要点:
当前元素的目标位置 index 有可能越上下界,多加两个判断条件;
如果真是 swap 了,不代表当前元素一定是正确位置,指针不要动(或者说在 for loop 里面要 i--)
研究区间类问题的时候做过一次,挺有意思的。
这题的要点在于 “不断更新 lower”,并且根据个新元素带来的区间终点决定是添加一个元素,还是一个区间。
这题是一个道理,我们依然用 first missing positive 的做法,把每个数试图换到它对应的位置上;然后 nums 数组最后的那个元素,一定是 duplicate element,因为其他元素都归位之后,它没地方去。因为如果最后一个元素是唯一元素的话,它一定会被置换到正确位置上。
好吧,写完了我才发现不让修改原数组= =
这题还有另一种很妖孽的写法,就是把它当成 LinkedList 做。。
那么这道题又跟Find the Duplicate Number有什么关系呢? 在table中每个元素存储的是table index,根据其跳转,其实就是把table中的元素作为指针来使用。就像我们在上题中也是在child node中存parent node的index,并做跳转。 我们结合Find the Duplicate Number这道题来看。这道题讨论区most voted的解法即是一个国人大神把它转化为了Linked List Cycle来做。 find linked list cycle是一道大家都很熟悉的题。而国人大神的解法就是把given array中的每一个元素当作指针来用跳转到下一个元素。 我们用A[1, 4, 3, 2, 5, 2, 6]来做例:
当我们扫到A[0]时,A[0] == 1,把它作为指针来使用,我们跳到A[1];
A[1] == 4, 跳到A[4];
A[4] == 5, 跳到A[5];
A[5] == 2, 跳到A[2];
A[2] == 3, 跳到A[3];
A[3] == 2, 开始循环...
这道题之所以可以把元素作为指针来使用当然也是题干出的巧。
这里要注意初始化问题,fast 要初始化成 nums[nums[0]],不然死循环。
(G面经)
然后是一道关于按照固定的顺序重新排序,多少次排序才能回到初始顺序的题目,我们总是把第x个位置的元素移到第y个位置,比如【0,1,2,3】就是完全不换顺序,一次排序就回去了;【3,2,1,0】是位置3和位置0互换,位置2和位置1互换,两次排序就能回到原顺序;而【1,2,3,0】就是每次把一个位置上的元素往后移动一个位置,那显然转一圈就回来了。
举个例子,原来的input为[20, 34, 7, 9], 排序要求为[1, 3, 2, 0] 一次排序后: [20, 34, 7, 9] -> [34, 9, 7, 20] 二次排序后: [34, 9, 7, 20] -> [9, 20, 7, 34] 三次排序后: [9, 20, 7, 34] -> [20, 34, 7, 9] (此时和初始顺序一致,所以是用了三个iteration恢复原样)
排序规则[1, 3, 2, 0]的意思是把在位置1的元素排到第0个位置,位置3的元素排到第2个位置,位置2的元素还是在位置2,位置0的元素放到位置3去。 排序规则不变,每次只是Input被按照规则改变了顺序。
这个小技巧也可以用在原帖第二轮第二题上。
原帖中Heliuhun对于这道题给了一个很精妙的解法。我们来分析一下这个解法。 用A[a1, a2, a3, a4, a5], B[1,0,4,2,3]做例: 我们并不在乎A中的每个数到底是什么。我们想知道的是A中的每个数按照B来移动,最少经过多少次可以回到原位。 对于a2来说,它经历一次移动从1来到了0的位置。再经历一次移动从0回到了1的位置。 对于a4来说,它经历一次移动从3来到了2的位置。再经历一次移动从2来到了4的位置。再经历一次移动从4回到了3的位置。 可以看到A中的元素是根据B来跳转的,并且把B中的元素当作指针来使用。B中的元素形成了一个或多个封闭的环状“linked list”。 按照Heliuhun的思路,我们需要找出B中有多少封闭的环状“linked list”,再找出它们的最小公倍数。 为什么是最小公倍数呢? 拿上面的例子来说,当a2经过两次移动后回到原位时,a4还需要一次移动才能回到原位。最少经过6次移动,a2,a4以及a1,a3,a5才能同时回到原位。
跳转序列可以拆成几个独立的环,同时也知道每个环的长度,然后求所有环长度的最小公倍数?比如[1,0,4,2,3]就是0-1-0 和 2-3-4-2两个环,所以6次shuffle后变回原来的数组
Least common multiple = 最小公倍数
Last updated