• [算法]位运算问题之二



    题目一:

    给定一个整形数组arr和一个大于1的整数k。已知arr中只有1个数出现了奇数次,其他的数都出现了偶数次,请返回出现了奇数次的数。

    时间复杂度为O(N),额外空间复杂度为O(1)。

    思路:

    整数n与0异或的结果是n,整数n与整数n异或的结果是0.所以先申请一个整形变量,记为eO。把eO和每个数异或(eO=eO^当前数),最后eO的值就是出现了奇数次的那个数。

    异或运算满足交换律和结合律。

    public static void printOddTimesNum1(int[] arr) {
            int eO = 0;
            for (int cur : arr) {
                eO ^= cur;
            }
            System.out.println(eO);
        }

    题目二:

    给定一个整形数组arr,有两个数出现了奇数次,其他数都出现了偶数次。打印这两个数。

    思路:

    如果只有a和b出现了奇数次,那么最后的异或结果eO一定是a^b。所以,如果数组中有两个出现了奇数次的数,最终的结果eO一定不为0.那么肯定能在32位整数eO上找到一个不等于0的bit位,假设是第K为不等于0。eO在第K位上不等于0,说明a和b的第k位肯定有一个是1另一个是0.接下来再设置一个变量记为eHasOne,然后再遍历一次数组。在这次遍历中,eHasOne只与第k位上是1的整数异或,其他的数被忽略。那么在第二次遍历结束后,eHasOne就是a或者b中的一个,而eO^eHasOne就是另外一个数。

    public static void printOddTimesNum2(int[] arr) {
            int eO = 0, eOhasOne = 0;
            for (int curNum : arr) {
                eO ^= curNum;
            }
            int rightOne = eO & (~eO + 1);
            for (int cur : arr) {
                if ((cur & rightOne) != 0) {
                    eOhasOne ^= cur;
                }
            }
            System.out.println(eOhasOne + " " + (eO ^ eOhasOne));
        }

    题目三:

    给定一个整形数组arr和一个大于1的整数k。已知arr中只有1个数出现了1次,其他的数都出现了k次,请返回只出现1次的数。

    思路:

    两个k进制的数a和b,在i位上无进位相加的结果就是(a(i)+b(i))%k。那么如果k个相同的k进制数进行无进位相加,相加的结果一定是每一位上都是0的k进制数。

    首先设置一个变量eO,它是一个32位的k进制数,且每个位置上都是0.然后遍历arr,把遍历到的每一个整数都转化为k进制数,然后与eO进行无进位相加。遍历结束时,把32位的k进制数eORes转化为十进制整数,就是最后的结果。因为k个相同的k进制数无进位相加,结果一定是每一位上都是0的k进制数,所以只出现一次的那个数就会剩下来。

    public static int onceNum(int[] arr, int k) {
            int[] eO = new int[32];
            for (int i = 0; i != arr.length; i++) {
                setExclusiveOr(eO, arr[i], k);
            }
            int res = getNumFromKSysNum(eO, k);
            return res;
        }
        //将当前数对应的k进制加到数组对应的位置
        public static void setExclusiveOr(int[] eO, int value, int k) {
            int[] curKSysNum = getKSysNumFromNum(value, k);
            for (int i = 0; i != eO.length; i++) {
                eO[i] = (eO[i] + curKSysNum[i]) % k;
            }
        }
        //将value转化为32位的k进制
        public static int[] getKSysNumFromNum(int value, int k) {
            int[] res = new int[32];
            int index = 0;
            while (value != 0) {
                res[index++] = value % k;
                value = value / k;
            }
            return res;
        }
        //根据最后数组中剩余的数字得到最后的结果
        public static int getNumFromKSysNum(int[] eO, int k) {
            int res = 0;
            for (int i = eO.length - 1; i != -1; i--) {
                res = res * k + eO[i];
            }
            return res;
        }
  • 相关阅读:
    2016年 IT 趋势大预测!
    怎样创建合适的告警处理流程?
    如何解决 Java 安全问题?
    程序员:如何成为一个全栈的工程师?
    安全防护:你是否正在追逐一个不可能实现的目标?
    如何使用 Python 创建一个 NBA 得分图?
    如何对 Android 库进行依赖管理?
    减少 WAF 漏报的 8 种方法 !
    第69节:Java中数据库的多表操作
    第69节:Java中数据库的多表操作
  • 原文地址:https://www.cnblogs.com/xiaomoxian/p/5164043.html
Copyright © 2020-2023  润新知