龙珠

修炼自己与发现世界

算法题:如何不使用第三个寄存器完成两个寄存器内容的互换?【存疑】

今天论坛十大有个Google的Linux小组成立的帖子,为了上十大竟然有人抛出了一道算法题。

想上十大很简单。比如提一下:一个朋友因为谷歌面试他的时候问他“如何不使用第三个寄存器完成两个寄存器内容的互换?”他回答不出来,于是被拒了。然后他发誓再也不考虑去谷歌工作。各位有什么看法吗?技术和非技术的角度都可以。

学习的时候都是使用第三方temp来存储数据的,从来没想过不使用第三个寄存器。

下面有人给出的解法:

A + B -> A

A - B -> B

A - B -> A

可以做加减法么 - -

唔,看起来好像很简单。不过能想出来就不容易了。

还有人说使用XOR(异或)更快。

另外有人担心:

突然想到做加法可能会溢出,xor 应该没问题

写代码测试了一下,代码如下:

public static void main(String[] argv){
        int[] a1 = {3,1,2,5,1,Integer.MIN_VALUE};
        int[] a2 = {5,2,9,3,Integer.MAX_VALUE,1111};
                                              
        System.out.println(Integer.MAX_VALUE);
        System.out.println(Integer.MAX_VALUE+1);
        System.out.println(Integer.MAX_VALUE+10);
        System.out.println((Integer.MAX_VALUE+1)-1);
        System.out.println((Integer.MAX_VALUE+10)-10);
                                                      
        System.out.println("Before Array Change. a1:"+
                Utils.getArrayString(a1)+" a2:"+Utils.getArrayString(a2));
        for(int i=0;i<a1.length;i++){
            a1[i] = a1[i] ^ a2[i];
            a2[i] = a1[i] ^ a2[i];
            a1[i] = a1[i] ^ a2[i];
        }
        System.out.println("After Array Change with ^. a1:"+
                Utils.getArrayString(a1)+" a2:"+Utils.getArrayString(a2));
                                                      
        for(int i=0;i<a1.length;i++){
            a1[i] = a1[i] + a2[i];
            a2[i] = a1[i] - a2[i];
            a1[i] = a1[i] - a2[i];
        }
        System.out.println("After Array Change with +/-. a1:"+
                Utils.getArrayString(a1)+" a2:"+Utils.getArrayString(a2));
    }

前面是测试使用Integer的MAX_VALUE做加减是否会溢出,后面是测试^和+/-方法。

运行结果如下:

2147483647
-2147483648
-2147483639
2147483647
2147483647
Before Array Change. a1:3 1 2 5 1 -2147483648  a2:5 2 9 3 2147483647 1111 
After Array Change with ^. a1:5 2 9 3 2147483647 1111  a2:3 1 2 5 1 -2147483648 
After Array Change with +/-. a1:3 1 2 5 1 -2147483648  a2:5 2 9 3 2147483647 1111

可以看到,使用Integer的MAX_VALUE最后进行+/-计算后,最后还是会正常的。下面的结果也证实了这一点。

因此,使用这两种方法是都行的。

另外,还有童鞋提到了XCHG,查了一下百科如下:

交换指令XCHG是两个寄存器,寄存器和内存变量之间内容的交换指令,两个操作数的数据类型要相同,可以是一个字节,也可以是一个字。其指令格式如下:

XCHG Reg/Mem, Mem/Reg,Reg/Reg

不过还是没看明白具体是如何实现的【存疑】。

这个基本思想是,对于没有多余空间的情况下的互换操作,需要将其中一个数组的值的信息加到另一个数组中,之后再操作将二者分离出来。

跟之前做的一道数组题思路很像:统计一个数组中出现次数为k的数,要求不使用额外空间。或者是:对数组排序,要求不使用额外空间。

这时,可以将原数组乘以数组长度N,之后将数出现一次则+1,最后对N取余数就是出现次数。排序中也可以通过+1来标注位置等信息。

总的来说,需要使用方法(A+B或A^B或A*N都行),将新的信息保存进去,这样才能不使用额外空间。

参考资料:

  1. [公告]GoogleCamp的Linux活动小组成立咧

  2. XCHG