使用数组并将重复项移动到末尾
我在一次采访中得到了这个问题,最后被告知有一种更有效的方法可以做到这一点,但仍然无法弄清楚。您正在向函数传递一个整数数组和一个表示数组大小的整数。在数组中有很多数字,其中一些数字是重复的,例如 1,7,4,8,2,6,8,3,7,9,10
。您想要获取该数组并返回一个数组,其中所有重复的数字都放在数组的末尾,因此上面的数组将变成 1,7,4,8,2,6,3,9,10 ,8,7
。我使用的数字并不重要,而且我无法使用缓冲区数组。我打算使用 BST,但必须保持数字的顺序(重复的数字除外)。我不知道如何使用哈希表,所以我最终使用了双 for 循环(我知道 n^2 可怕)。我如何使用 C++ 更有效地做到这一点。不是在寻找代码,只是想知道如何做得更好。
I got this question at an interview and at the end was told there was a more efficient way to do this but have still not been able to figure it out. You are passing into a function an array of integers and an integer for size of array. In the array you have a lot of numbers, some that repeat for example 1,7,4,8,2,6,8,3,7,9,10
. You want to take that array and return an array where all the repeated numbers are put at the end of the array so the above array would turn into 1,7,4,8,2,6,3,9,10,8,7
. The numbers I used are not important and I could not use a buffer array. I was going to use a BST, but the order of the numbers must be maintained(except for the duplicate numbers). I could not figure out how to use a hash table so I ended up using a double for loop(n^2 horrible I know). How would I do this more efficiently using c++. Not looking for code, just an idea of how to do it better.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
其中:
arr
是输入数组;seen
是已经遇到的数字的哈希集;l
是放置下一个唯一元素的索引;r
是要考虑的下一个元素的索引。由于您不是在寻找代码,因此这里有一个伪代码解决方案(恰好是有效的 Python):
在您的测试用例中,这会产生
In what follows:
arr
is the input array;seen
is a hash set of numbers already encountered;l
is the index where the next unique element will be placed;r
is the index of the next element to be considered.Since you're not looking for code, here is a pseudo-code solution (which happens to be valid Python):
On your test case, this produces
我将使用一个附加映射,其中键是数组中的整数值,该值是在开始时设置为 0 的整数。现在,如果键已在地图中,我将遍历数组并增加地图中的值。
最后我会再次遍历数组。当数组中的整数在映射中的值为 1 时,我不会更改任何内容。当它在映射中的值为 2 或更大时,我会将数组中的整数与最后一个整数交换。
这应该导致运行时间为 O(n*log(n))
I would use an additional map, where the key is the integer value from the array and the value is an integer set to 0 in the beginning. Now I would go through the array and increase the values in the map if the key is already in the map.
In the end I would go again through the array. When the integer from the array has a value of one in the map, I would not change anything. When it has a value of 2 or more in the map I would swap the integer from the array with the last one.
This should result in a runtime of O(n*log(n))
我这样做的方法是创建一个两倍于原始大小的数组并创建一组整数。
然后循环遍历原始数组,将每个元素添加到集合中,如果它已经存在,则将其添加到新数组的第二半,否则将其添加到新数组的前半部分。
最后你会得到一个看起来像这样的数组:(使用你的例子)
1,7,4,8,2,6,3,9,10,-,-,8,7,-,-,-,- ,-,-,-,-,-
然后我会再次循环原始数组,并使每个点等于下一个非空位置(或 0'd 或您决定的任何位置),
这将使原始数组变成您的解决方案...
这最终是 O(n) ,大约为我能想到的高效
The way I would do this would be to create an array twice the size of the original and create a set of integers.
Then Loop through the original array, add each element to the set, if it already exists add it to the 2nd half of the new array, else add it to the first half of the new array.
In the end you would get an array that looks like: (using your example)
1,7,4,8,2,6,3,9,10,-,-,8,7,-,-,-,-,-,-,-,-,-
Then I would loop through the original array again and make each spot equal to the next non-null position (or 0'd or whatever you decided)
That would make the original array turn into your solution...
This ends up being O(n) which is about as efficient as I can think of
我已经失去联系有一段时间了,但我可能会从这样的事情开始,看看它如何随着更大的输入而扩展。我知道您没有要求代码,但在某些情况下它比解释更容易理解。
编辑:抱歉,我错过了不能使用缓冲区数组的要求。
I have been out of touch for a while, but I'd probably start out with something like this and see how it scales with larger input. I know you didn't ask for code but in some cases it's easier to understand than an explanation.
Edit: Sorry I missed the requirement that you cannot use a buffer array.
检查
排序
和独特
。Check
sort
andunique
.http://ideone.com/3choA
并不是说我会提交评论不佳的代码。另请注意,unordered_set 可能在内部使用它自己的数组,大于
data
。 (这已经根据aix的答案重写了,速度更快)http://ideone.com/3choA
Not that I would turn in code this poorly commented. Also note that unordered_set probably uses it's own array internally, bigger than
data
. (This has been rewritten based on aix's answer, to be much faster)如果您知道整数值的界限
B
以及整数数组的大小SZ
,那么您可以执行如下操作:B
元素的布尔值seen_before
,初始化为 0。SZ
元素创建一个由整数组成的结果数组result
。front_pos = 0
,一个用于back_pos = SZ - 1
。val
设置为当前元素的值seen_before[val]
设置为 1,则将数字放入result[back_pos]
,然后递减back_pos
seen_before[val]
未设置为 1,则将数字放入result[front_pos]
,然后递增front_pos
并设置seen_before[val]
为 1。完成对主列表的迭代后,所有唯一数字将位于列表的前面,而重复的数字将位于列表的前面。在后面。有趣的是,整个过程一次性完成。请注意,只有当您知道原始数组中出现的值的边界时,这才有效。
编辑:有人指出,所使用的整数没有限制,因此不要将
seen_before
初始化为包含B
元素的数组,而是将其初始化作为map
,然后照常继续。这应该会给你带来 n*log(n) 的性能。If you know the bounds on what the integer values are,
B
, and the size of the integer array,SZ
, then you can do something like the following:seen_before
withB
elements, initialized to 0.result
of integers withSZ
elements.front_pos = 0
, one forback_pos = SZ - 1
.val
to the value of the current elementseen_before[val]
is set to 1, put the number atresult[back_pos]
then decrementback_pos
seen_before[val]
is not set to 1, put the number atresult[front_pos]
then incrementfront_pos
and setseen_before[val]
to 1.Once you finish iterating across the main list, all the unique numbers will be at the front of the list while the duplicate numbers will be at the back. Fun part is that the entire process is done in one pass. Note that this only works if you know the bounds of the values appearing in the original array.
Edit: It was pointed out that there's no bounds on the integers used, so instead of initializing
seen_before
as an array withB
elements, initialize it as amap<int, bool>
, then continue as usual. That should get you n*log(n) performance.这可以通过迭代数组来完成第一个变化的标记索引。
稍后将该标记索引值与下一个唯一值交换
&然后递增该标记索引以进行下一次交换
Java 实现:
输出为 1 7 4 8 2 6 3 9 10 8 7
This can be done by iterating the array & marking index of the first change.
later on swaping that mark index value with next unique value
& then incrementing that mark index for next swap
Java Implementation:
output is 1 7 4 8 2 6 3 9 10 8 7
虽然很难看,但是满足了将重复项原地移动到末尾的要求(无缓冲区数组)
It's ugly, but it meets the requirements of moving the duplicates to the end in place (no buffer array)
如果输入数组为{1,7,4,8,2,6,8,3,7,9,10},则输出为{1,7,4,8,2,6,10,3, 9,7,8}。与你的答案{1,7,4,8,2,6,3,9,10,8,7}相比,前半部分是相同的,而右半部分是不同的,因为我用尾部交换了所有重复项数组的。正如您所提到的,重复项的顺序可以是任意的。
If the input array is {1,7,4,8,2,6,8,3,7,9,10}, then the output is {1,7,4,8,2,6,10,3,9,7,8}. Comparing with your answer {1,7,4,8,2,6,3,9,10,8,7}, the first half is the same, while the right half is different, because I swap all duplicates with the tail of the array. As you mentioned, the order of the duplicates can be arbitrary.