给定一个由三个数字组成的数组,我想知道其中间的值。
问题是,找出这三个数字中的中间数的最快方法是什么?
我的方法是这样的模式-因为有三个数字,所以有六种排列方式:
if (array[randomIndexA] >= array[randomIndexB] &&
array[randomIndexB] >= array[randomIndexC])
如果有人能帮我找到一种更优雅且更快速的方法,那真是太好了。
给定一个由三个数字组成的数组,我想知道其中间的值。
问题是,找出这三个数字中的中间数的最快方法是什么?
我的方法是这样的模式-因为有三个数字,所以有六种排列方式:
if (array[randomIndexA] >= array[randomIndexB] &&
array[randomIndexB] >= array[randomIndexC])
如果有人能帮我找到一种更优雅且更快速的方法,那真是太好了。
在这里有一个使用min/max而没有分支的答案(https://dev59.com/wXI-5IYBdhLWcg3w-9wK#14676309)。实际上,只需要4个min/max操作即可找到中位数,无需使用异或:
median = max(min(a,b), min(max(a,b),c));
虽然它无法给出中位数的索引...
所有情况的详细说明:
a b c
1 2 3 max(min(1,2), min(max(1,2),3)) = max(1, min(2,3)) = max(1, 2) = 2
1 3 2 max(min(1,3), min(max(1,3),2)) = max(1, min(3,2)) = max(1, 2) = 2
2 1 3 max(min(2,1), min(max(2,1),3)) = max(1, min(2,3)) = max(1, 2) = 2
2 3 1 max(min(2,3), min(max(2,3),1)) = max(2, min(3,1)) = max(2, 1) = 2
3 1 2 max(min(3,1), min(max(3,1),2)) = max(1, min(3,2)) = max(1, 2) = 2
3 2 1 max(min(3,2), min(max(3,2),1)) = max(2, min(3,1)) = max(2, 1) = 2
clamp(x, L, H) = max(L, min(H, x))
时,求三个数的中位数可表示为clamp(c, min(a,b), max(a,b))
。 - Řrřola如果硬件可以在没有分支的情况下回答min和max查询(大多数现代CPU都可以做到这一点),则可以回答该查询。
运算符^表示按位异或。
Input: triple (a,b,c)
1. mx=max(max(a,b),c)
2. mn=min(min(a,b),c)
3. md=a^b^c^mx^mn
4. return md
这是正确的,因为:
应选择适当的min/max函数用于int/float类型。如果只有正的浮点数存在,则可以直接在浮点表示上使用整数min/max(这可能是有利的,因为整数操作通常更快)。
在硬件不支持min/max的不太可能的情况下,可以执行类似以下操作:
max(a,b)=(a+b+|a-b|)/2
min(a,b)=(a+b-|a-b|)/2
然而,在使用浮点数操作时,这不是正确的,因为需要精确的最小值/最大值,而不是接近它的值。幸运的是,浮点数的最小值/最大值在硬件上已经得到了支持很久了(在x86平台,从Pentium III及以后版本的处理器都支持)。
b+|a
的意思是什么?+
和 |
都是二进制运算符。 - Ajaymin = (a < b) ? (a < c) ? a : c : (b < c) ? b : c;
and
max = (a > b) ? (a > c) ? a : c : (b > c) ? b : c;
- mckamey如果你正在寻找最高效的解决方案,我认为它应该类似于这样:
if (array[randomIndexA] > array[randomIndexB]) {
if (array[randomIndexB] > array[randomIndexC]) {
return "b is the middle value";
} else if (array[randomIndexA] > array[randomIndexC]) {
return "c is the middle value";
} else {
return "a is the middle value";
}
} else {
if (array[randomIndexA] > array[randomIndexC]) {
return "a is the middle value";
} else if (array[randomIndexB] > array[randomIndexC]) {
return "c is the middle value";
} else {
return "b is the middle value";
}
}
这种方法至少需要两次比较,最多需要三次比较。它故意忽略了两个值相等的可能性(就像你的问题一样):如果这很重要,该方法也可以扩展以检查这一点。
最多只需要两次比较就可以完成此操作。
int median(int a, int b, int c) {
if ( (a - b) * (c - a) >= 0 ) // a >= b and a <= c OR a <= b and a >= c
return a;
else if ( (b - a) * (c - b) >= 0 ) // b >= a and b <= c OR b <= a and b >= c
return b;
else
return c;
}
((long)b - c)
可以重复使用((long)a - b)
。 - greybeard还有一个想法。有三个数字{a,b,c}
。那么:
middle = (a + b + c) - min(a,b,c) - max(a,b,c);
当然,我们必须记住数字限制...
min()
或 max()
函数。 - Celeritasmin(a,b,c) = min(a,min(b,c))
- sim642int a, b, c = ...
int middle = (a <= b)
? ((b <= c) ? b : ((a < c) ? c : a))
: ((a <= c) ? a : ((b < c) ? c : b));
编辑:
我没有看到一个实现交换的解决方案:
int middle(int a, int b, int c) {
// effectively sort the values a, b & c
// putting smallest in a, median in b, largest in c
int t;
if (a > b) {
// swap a & b
t = a;
a = b;
b = t;
}
if (b > c) {
// swap b & c
t = b;
b = c;
c = t;
if (a > b) {
// swap a & b
t = a;
a = b;
b = t;
}
}
// b always contains the median value
return b;
}
顶一下旧帖,但它仍然是最简单的解决方案,并没有人提到过。
int median2(int a, int b, int c) {
return (a > b) ^ (a > c) ? a : (a > b) ^ (b > c) ? c : b;
}
(测试覆盖所有可能的组合,所有测试都打印6)
public static void main(String[] args) {
System.out.println(median(3, 6, 9));
System.out.println(median(3, 9, 6));
System.out.println(median(6, 3, 9));
System.out.println(median(6, 9, 3));
System.out.println(median(9, 3, 6));
System.out.println(median(9, 6, 3));
System.out.println(median(6, 6, 3));
System.out.println(median(6, 6, 9));
System.out.println(median(6, 3, 6));
System.out.println(median(6, 9, 6));
System.out.println(median(3, 6, 6));
System.out.println(median(9, 6, 6));
System.out.println(median(6, 6, 6));
}
(a > b) ^ (a > c)
如果 c > a > b
或者 c < a < b
则为假 - 返回 a
;
否则,(a > b) ^ (b > c)
如果 a > b > c
或者 a < b < c
则为假 - 返回 b
;
否则返回 c
;
假设 p = a > b
; q = b > c
; s = a > c
;
让我们构建一个卡诺图。
| 00 01 11 10 (p, q)
---+----------------------
0 | b c * a
1 | * a b c
(s)|
*
表示组合不可能(比如 a > b; b > c; a < c
)。
请注意,右侧部分是左侧部分的镜像,并且可以通过引入 t = p ^ q; u = s ^ p
来简化映射。
| 0 1 (t)
---+---------
0 | b c
1 | * a
(u)|
private static int median(int a, int b, int c) {
boolean t = (a > b) ^ (b > c);
boolean u = (a > b) ^ (a > c);
if (u)
return a;
else if (t)
return c;
else
return b;
}
内联变量和用?:替换if语句可以得到答案
int median2(int a, int b, int c) {
return (a > b) ^ (a > c) ? a : (a > b) ^ (b > c) ? c : b;
}
中位数 = (a+b+c) - Math.min(Math.min(a,b),c) - Math.max(Math.max(a,b),c)
这是基本的方法,我不知道它的效率如何,但这些函数毕竟使用了if条件语句。如果您愿意,可以将此语句转换为if-else语句,但这需要时间。为什么这么懒呢?