我在公司面试中看到了这个问题,但我不清楚这个问题。你能否澄清我的疑问?
问题:编写一个程序来对整数数组进行排序,该数组只包含0,1和2。计算不允许的元素,你应该在O(n)时间复杂度下进行。
Ex数组:{2,0,1,2,1,2,1,0,2,0}
答案 0 :(得分:10)
输出到链接列表。
贯穿整个阵列。
HTH
乐
答案 1 :(得分:4)
我没有用另一个难以理解的伪代码给你爆炸,而是给你问题的名称:这个问题被称为Dutch national flag problem(由Edsgar Dijkstra首先提出)并且可以通过三方合并(请参阅第一个解决此问题的PHP代码,尽管效率非常低)。
Bentley和McIlroy的开创性论文Engineering a Sort Function中描述了三通合并的更有效的就地解决方案。它使用四个索引来划分中间数组的范围,中间数组的中间值为未排序值,两端为1,中间为0和2:
在建立了这个不变量之后,=
部分(即1s)被换回中间。
答案 2 :(得分:3)
这取决于你的意思是“不计算允许”。
执行此操作的一种简单方法是使用新的空数组,然后查找0,将它们附加到新数组。重复1次,然后是2次,并在O(n)时间内进行排序。
但这或多或少是基数排序。这就像我们计算的是0然后是1然后是2,所以我不确定这是否符合你的标准。
编辑:我们只需要O(1)额外内存就可以通过保持指针插入点(从数组的开头开始),并在数组中扫描0来进行交换,然后用元素交换每个0指针是,并递增指针。然后重复1次,2次,它仍然是O(n)。
Java实现:
import java.util.Arrays;
public class Sort
{
public static void main(String[] args)
{
int[] array = {2, 0, 1, 2, 1, 2, 1, 0, 2, 0};
sort(array);
System.out.println(Arrays.toString(array));
}
public static void sort(int[] array)
{
int pointer = 0;
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < array.length; j++)
{
if(array[j] == i)
{
int temp = array[pointer];
array[pointer] = array[j];
array[j] = temp;
pointer++;
}
}
}
}
}
提供输出:
[0,0,0,1,1,1,2,2,2,2]
答案 3 :(得分:1)
对不起,这是php,但似乎O(n)并且可以很容易用java编写:)
$arr = array(2, 0, 1, 2, 1, 2, 1, 0, 2, 0);
$tmp = array(array(),array(),array());
foreach($arr as $i){
$tmp[$i][] = $i;
}
print_r(array_merge($tmp[0],$tmp[1],$tmp[2]));
答案 4 :(得分:1)
在O(n)中,伪代码:
def sort (src):
# Create an empty array, and set pointer to its start.
def dest as array[sizeof src]
pto = 0
# For every possible value.
for val in 0, 1, 2:
# Check every position in the source.
for pfrom ranges from 0 to sizeof(src):
# And transfer if matching (includes update of dest pointer).
if src[pfrom] is val:
dest[pto] = val
pto = pto + 1
# Return the new array (or transfer it back to the source if desired).
return dest
这基本上是在源列表上迭代三次,如果它们匹配此传递所需的值,则添加元素。但它仍然是O(n)。
等效的Java代码是:
class Test {
public static int [] mySort (int [] src) {
int [] dest = new int[src.length];
int pto = 0;
for (int val = 0; val < 3; val++)
for (int pfrom = 0; pfrom < src.length; pfrom++)
if (src[pfrom] == val)
dest[pto++] = val;
return dest;
}
public static void main(String args[]) {
int [] arr1 = {2, 0, 1, 2, 1, 2, 1, 0, 2, 0};
int [] arr2 = mySort (arr1);
for (int i = 0; i < arr2.length; i++)
System.out.println ("Array[" + i + "] = " + arr2[i]);
}
}
输出:
Array[0] = 0
Array[1] = 0
Array[2] = 0
Array[3] = 1
Array[4] = 1
Array[5] = 1
Array[6] = 2
Array[7] = 2
Array[8] = 2
Array[9] = 2
但严重的是,如果一个潜在的雇主给了我这个问题,我会直截了当地表示如果他们愿意我可以回答这个问题,但正确的答案就是使用{{1 }}。然后,如果,仅,如果该方法和特定数据集存在性能问题,您可以更快地调查。
这种更快的方式几乎肯定会涉及计数,尽管有这些要求。您不会因任意限制而妨碍您的开发人员。要求应指定所需的,而不是如何。
如果你以这种方式回答我这个问题,我会当场雇用你。
答案 5 :(得分:0)
此答案不计算元素。
由于数组中的值太少,只需计算每种类型的数量,并使用它来重新填充数组。我们还利用了值从0开始连续的事实 - 使其与典型的java int循环匹配。
public static void main(String[] args) throws Exception
{
Integer[] array = { 2, 0, 1, 2, 1, 2, 1, 0, 2, 0 };
List<Integer>[] elements = new ArrayList[3]; // To store the different element types
// Initialize the array with new lists
for (int i = 0; i < elements.length; i++) elements[i] = new ArrayList<Integer>();
// Populate the lists
for (int i : array) elements[i].add(i);
for (int i = 0, start = 0; i < elements.length; start += elements[i++].size())
System.arraycopy(elements[i].toArray(), 0, array, start, elements[i].size());
System.out.println(Arrays.toString(array));
}
输出:
[0, 0, 0, 1, 1, 1, 2, 2, 2, 2]
答案 6 :(得分:0)
Push and Pull具有持续的复杂性!
将每个元素推送到优先级队列
将每个元素拉到索引0 ... n
(:
答案 7 :(得分:0)
你可以一次完成,将每个遇到的元素放在它的最终位置:
void sort012(int* array, int len) {
int* p0 = array;
int* p2 = array + len;
for (int* p = array; p <= p2; ) {
if (*p == 0) {
std::swap(*p, *p0);
p0++;
p++;
} else if (*p == 2) {
std::swap(*p, *p2);
p2--;
} else {
p++;
}
}
}
答案 8 :(得分:-4)
由于数组中的值太少,只需 count 每种类型有多少,并使用它来重新填充数组。我们还利用了值从0开始连续的事实 - 使其与典型的java int循环匹配。
整个排序算法只需要三行代码:
public static void main(String[] args)
{
int[] array = { 2, 0, 1, 2, 1, 2, 1, 0, 2, 0 };
// Line 1: Define some space to hold the totals
int[] counts = new int[3]; // To store the (3) different totals
// Line 2: Get the total of each type
for (int i : array) counts[i]++;
// Line 3: Write the appropriate number of each type consecutively back into the array:
for (int i = 0, start = 0; i < counts.length; start += counts[i++]) Arrays.fill(array, start, start + counts[i], i);
System.out.println(Arrays.toString(array));
}
输出:
[0, 0, 0, 1, 1, 1, 2, 2, 2, 2]
我们在任何时候都没有提到array.length
,也没关心数组的长度。它迭代遍历每个元素触摸一次的数组,使得该算法O(n)成为必需。