[算法]位运算之二


题目一:

给定一个整形数组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;
    }
时间: 2024-10-18 21:45:49

[算法]位运算之二的相关文章

java加密解密算法位运算

一.实例说明 本实例通过位运算的异或运算符 “ ^ ” 把字符串与一个指定的值进行异或运算,从而改变每个字符串中字符的值,这样就可以得到一个加密后的字符串.当把加密后的字符串作为程序输入内容,异或运算会把加密后的字符串还原为原有字符串的值.效果图如下: 二.实现过程 1 package com.itxxz; 2 3 import java.util.Scanner; 4 5 /** 6 * java加密解密算法 7 * 8 * @author 螃蟹 9 * 网站:IT学习者 10 * 网址:ht

剑指offer—算法之位运算(二进制中1的个数)

位运算: 左移:m<<n将m左移n位,左移后低位补充0: 右移:m>>n将m右移n位,右移后高位补充的是符号位,负数补充1,整数补充0.(正数的边界值为(1,ox7FFFFFFF),负数的边界值为(ox80000000,oxFFFFFFFF)) 题目一:请实现一个函数,输入一个整数,输出这个数的二进制表示中1的个数. 思路一:将二进制数i与1相与,判断是否为1,然后将tag=1左移一位得到tag=2,然后再与i相与,循环结束的条件是tag==0:该算法的时间复杂度为输入的i的位数.

数据结构与算法-位运算

位运算位运算是把数字用二进制表示之后,对每一位上的0或者1的运算.理解位运算的第一步是理解二进制.二进制是指数字每一位都是0或者1,如十进制的2转换为二进制之后是10,而十进制的10转换为二进制之后是1010.在程序员圈子里有一个流传了很久的笑话,说世界上有10种人,一种人知道二进制,另一种人不知道二进制. 下面是几个常见的关于位运算的算法题:基本位运算位运算总共只有5种运算:与&,或|,异或^,左移<<,右移>>.与,或,异或的运算规则: 左移,右移运算规则:左移运算m

Apriori算法-位运算-C语言

原文地址:http://blog.csdn.net/liema2000/article/details/6118423 ///////////////////////////////////////////////////////////////////////////** 文件名称:FAST apriori.cpp * 摘 要:采用位运算提高算法的效率 * 将每一项抽象为数值,通过与运算判断是否存在,abcde为16,8,4,2,1换成2进制,各占一个位置,互相不干扰.局限于字母.换算的比较字

算法——位运算

&:按位与. |  :按位或. ~ :按位取反,带符号位.(注意和!的区别,!只是逻辑取反)  ^ : 异或也叫半加运算:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0. >> : 表示右移,算数右移,如果该数为正,高位补符. >>>:表示无符号右移,也叫逻辑右移,高位补零. 小操作: 1. 判断奇偶数 a & 1 2. 交换变量 a ^= b, b ^= a, a ^= b 3. 乘以(除以)2的n次方:左移,右移:取模运算:a % (2 ^ n) 等价于

[算法]位运算问题之一

一.不用额外变量交换两个整数的值 a=a^b; b=a^b; a=a^b; 或者: a=a+b; b=a-b; a=a-b; 二.不同任何比较判断找出两个数中较大 有两种方法,方法一有一定的局限性,a-b的值可能溢出,这样溢出后符号改变,返回结果就不正确. 而方法二对a和b是否异号进行了判断,如果同号,则按照方法一返回,否则直接返回正的数就行. a-b的值如果为0的处理按照大于0处理. //如果n为1,则返回0:如果n为0,则返回1 public static int flip(int n) {

[算法]位运算问题之三(实现加减乘除)

题目: 给定32位整数a和b,可正.可负.可0,不能使用算术运算符,可分别实现a和b的加减乘除运算. 加法运算: 无进位相加: a: 001010101 b: 000101111 a^b 001111010 只考虑进位: a   001010101 b   000101111 (a&b)<<1 000001010 把完全不考虑进位的相加值与只与考虑进位的产生值再相加,就是最后的结果.重复这样的过程,直到进位产生的值完全消失,说明所有的过程都加完了. public static int

[算法]位运算实现加减法

异或可以实现不考虑进位的加法,相同为0,不同为1 0101 ^ 0001 = 0100 两个数相加不考虑进位从二进制角度上说就是相同为0,不同为1,因为二进制只有两个数1和0 1+1=0 0+1=1 与运算可以实现进位 同为1才为1 0101 & 0001 = 0001 说明最低位有进位 int add(int a, int b) { return b == 0 ? a : add(a ^ b, (a & b) << 1); } 左移一位表示 将进位加到前一位 递归表示要遍历进

奇妙的位运算(二)

上篇的链接为:http://www.cnblogs.com/jiu0821/p/4677184.html 这次是偶然看到一个题目,很好玩,便记在这里吧! Bitwise AND of Numbers Range 给出一个范围,[m, n](0 <= m <= n <= 2147483647),返回这些数字的与运算结果. 直接逐个做与运算,TLE,我们得发现高效解法. 我们把[0, 15]用二进制码表示出来: 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 1 0 1 0 0