azl397985856 / fe-interview

宇宙最强的前端面试指南 (https://lucifer.ren/fe-interview)
Apache License 2.0
2.84k stars 260 forks source link

【每日一题】- 2019-08-23 - 不借助变量交换两个数 #21

Closed azl397985856 closed 5 years ago

azl397985856 commented 5 years ago

不借助变量交换两个数。

比如 a = 2, b = 3;

如果交换变量的值,使得a = 3, b = 2, 要求不能使用额外的变量

rosong1 commented 5 years ago

[a, b] = [b, a]

wuyuchang commented 5 years ago

传统方法需要借助第三变量,保存其值,如下:

var a = 1, b = 2, temp;
temp = a;
a = b;
b = temp;

对于整数,我们有如下方法,但仅支持整数:

a = a + b
b = a - b
a = a - b
a = a ^ b
b = a ^ b
a = a ^ b

对于所有数值,我们可以借助逗号运算符是从左到右运算的,

a = b + ( b = a, 0)

使用ES6语法可以方便的交换所有类型的值

[a, b] = [b, a]

不使用ES6可以借用数组来交换

b = [a, a = b][0]
wjjhhh commented 5 years ago

a = a ^ b b = a ^ b a = a ^ b

hjx5309 commented 5 years ago

[a, b] = [b, a]

azl397985856 commented 5 years ago

领取

azl397985856 commented 5 years ago

不借助变量交换两个数

借助额外的变量

在正式解这道题之前,我们先用最基础的借助额外变量的方法回忆一下。

var a = 1;
var b = 2;
var temp = a;
a = b;
b = temp;

这个过程就像交换两个杯子中的水一样。

如果不借助另外的变量,显然我们无法类比到交换两杯水。 我们需要别的办法。

利用加法

这是最容易想到的方法,代码如下:

var a = 1;
var b = 2;
b = a + b;
a = b - a;
b = b - a;

但是 a 和 b 的和溢出的风险,其实我们只要稍加变通一下即可。

我们来看下面的代码。

利用减法

var a = 1;
var b = 2;
b = a - b;
a = a - b;
b = a + b;

这种解法没有溢出的风险,理论上已经非常完美了,难道还有更优的解法么?

我们来看一种更加高效的做法。

异或

这里用到了异或这个位运算的性质,即相同则为 0,不同则为 1.

于是对于两个数字,a 和 b。则有 a ^ a ^ b 就等于 b 。 我们可以利用这个性质来完成交换。

有些算法题就可以用这个性质轻松解决

var a = 1;
var b = 2;
b = a ^ b;
a = a ^ b;
b = a ^ b;

逗号表达式

@wuyuchang 的方法。

利用了逗号表达式的性质。

什么是逗号表达式? 逗号表达式是将两个及其以上的式子联接起来,从左往右逐个计算表达式,整个表达式的值为最后一个表达式的值。

因此我们可以利用这个性质,先完成一次赋值操作,然后将赋值操作的返回值变为0. 就可以完成赋值操作

代码如下:

a = b + ((b = a), 0);

扩展

如果数字非常大怎么办? 由于数字非常大, 因此我们不能用数字存储了(也不能用 Bit Int)。 我们只能使用别的方式存储,比如字符串。 这个时候我们不能转化为数字,然后做四则运算, 那么我们怎么办?

这个其实我们可以自己实现一个“加法”或者“减法”,然后思路就和上面一样了。 关于这部分,可以参考大数相加实现加法

azl397985856 commented 5 years ago

传统方法需要借助第三变量,保存其值,如下:

var a = 1, b = 2, temp;
temp = a;
a = b;
b = temp;

对于整数,我们有如下方法,但仅支持整数:

a = a + b
b = a - b
a = a - b
a = a ^ b
b = a ^ b
a = a ^ b

对于所有数值,我们可以借助逗号运算符是从左到右运算的,

a = b + ( b = a, 0)

使用ES6语法可以方便的交换所有类型的值

[a, b] = [b, a]

不使用ES6可以借用数组来交换

b = [a, a = b][0]

es6属于犯规, 实际上还是会创建额外变量,你可以尝试使用babel转义看一下。 虽然引擎实现和babel不一样,不过应该差不多可以参考