算法26-----位运算

目录:

  技巧:

应用技巧1:x&(x-1)【消除x(二进制)最后一位1】

        • 判断是否为2的幂

应用技巧2:<<左移【除2】

        • 判断是否为2的幂
        • 判断是否为4的幂

应用技巧3:>>右移【×2】结合&1【判断最后一位是否为1】

应用技巧4:子集【根据二进制来打印子集】

应用技巧5:异或【两个相同的数异或结果为0】

题目:

      1. 如何不用额外空间交换两个变量
      2. 不用任何比较判断找出两个数中较大的数
      3. 只用位运算不用算术运算实现整数的加减乘除运算
      4. 整数的二进制表达中有多少个1
      5. 在其他数都出现偶数次的数组中找到出现奇数次的数
      6. 在其他数都出现K次的数组中找到只出现一次的数
      7. 请设置一种加密过程,完成对明文text的加密和解密工作。
      8. 数的幂【 举例:10^1101 = 10^0001*10^0100*10^1000】

技巧:

1、应用技巧1:与&【消除x(二进制)最后一位1】

def checkPowerof2(x):
    return x>0 and x&(x-1)==0

应用技巧二:判断n是否为4的幂:

def isFour(n):
    m=1
    while m<n:
        m=m<<2
    return m==n

 

 3、应用技巧3:>>右移【×2】结合&1 

题目:

  You are given an array A1,A2...AN. You have to tell how many pairs (i, j) exist such that 1 ≤ i < j ≤ N and AiXOR Aj is odd.

  

思路:判断列表数据中最后一位是0的个数和1的个数,两者相乘即为结果。

代码:

T = int(input())
for i in range(T):
    N = int(input())
    res = 0
    arr = list(map(int,input().split()))
    odd , even = 0 , 0
    for i in range(N):
        if arr[i]&1:
            odd += 1
        else:
            even += 1
    print(odd * even)

 

4、应用技巧4:子集

// Non Recursion
class Solution {
    /** * @param S: A set of numbers. * @return: A list of lists. All valid subsets. */ public List<ArrayList<Integer>> subsets(int[] nums) { List<ArrayList<Integer>> result = new ArrayList<List<Integer>>(); int n = nums.length; Arrays.sort(nums); // 1 << n is 2^n // each subset equals to an binary integer between 0 .. 2^n - 1 // 0 -> 000 -> [] // 1 -> 001 -> [1] // 2 -> 010 -> [2] // .. // 7 -> 111 -> [1,2,3] for (int i = 0; i < (1 << n); i++) { List<Integer> subset = new ArrayList<Integer>(); for (int j = 0; j < n; j++) { // check whether the jth digit in i's binary representation is 1 if ((i & (1 << j)) != 0) { subset.add(nums[j]); } } result.add(subset); } return result; } }

 

5、应用技巧5:异或

 

java代码:

public class Solution {
    public int singleNumber(int[] nums) { int ones = 0, twos = 0; for(int i = 0; i < nums.length; i++){ ones = (ones ^ nums[i]) & ~twos; twos = (twos ^ nums[i]) & ~ones; } return ones; } }

public class Solution {
    public int[] singleNumber(int[] nums) { //用于记录,区分“两个”数组 int diff = 0; for(int i = 0; i < nums.length; i ++) { diff ^= nums[i]; } //取最后一位1 //先介绍一下原码,反码和补码 //原码,就是其二进制表示(注意,有一位符号位) //反码,正数的反码就是原码,负数的反码是符号位不变,其余位取反 //补码,正数的补码就是原码,负数的补码是反码+1 //在机器中都是采用补码形式存 //diff & (-diff)就是取diff的最后一位1的位置 diff &= -diff; int[] rets = {0, 0}; for(int i = 0; i < nums.length; i ++) { //分属两个“不同”的数组 if ((nums[i] & diff) == 0) { rets[0] ^= nums[i]; } else { rets[1] ^= nums[i]; } } return rets; } }

 题目:

1、如何不用额外空间交换两个变量:

2、不用任何比较判断找出两个数中较大的数

法一:得到a-b的值的符号,若a-b是负数,则返回b,否则a。【存在溢出风险,a、b正负不同时,相减会溢出】

法二:

 

c = a-b,sign(c),sign(a),sign(b):表示a,b,c的正负

sign(a) == sign(b):则不会溢出,sign(c)>0则返回a,否则返回b

sign(a) != sign(b):返回sign(a)、sign(b)大的一个。

3、只用位运算不用算术运算实现整数的加减乘除运算

给定两个32位整数a,b,可正,可负,可0,不能使用算术运算符,分别实现a和b的加减乘除运算。

加法思路:

两个运算【异或】以及【&加左移<<】。

不考虑进位:a^b

仅考虑进位:(a&b)<<1

将上面两个不断相加直到没有进位产生为最终结果。

代码:

def add(a,b):
    sum = a
    while b!=0:
        sum = a^b
        b = (a&b)<<1
        a = sum
    return sum
a = 19
b = 12
add(a,b)

 减法思路:a-b 实现a+(-b)即可。b取反加1(补码)即为-b

#加法
def add(a,b):
    sum = a
    while b!=0:
        sum = a^b
        b = (a&b)<<1
        a = sum
    return sum

#减法
#取反加1得-b
def negNum(b):
    return add(~b,1)
#a+(-b)
def minus(a,b):
    return add(a,negNum(b))
    
a = 19
b = 12
minus(a,b)

乘法运算:

代码:

除法思路:

代码:

4、整数的二进制表达中有多少个1

给定一个32位整数n,可为0,可为正,也可为负,返回该整数二进制表达中1的个数。

简单思路:右移判断1的个数(循环32次)

循环次数更少的思路:1的个数次数

 法3:循环次数和法2一样:

 

法四:平行算法:

 

5、在其他数都出现偶数次的数组中找到出现奇数次的数

给定一个整型数组arr,其中只有一个数出现了奇数次,其他的数都出现了偶数次i,打印这个数。

进阶问题:有两个数出现了奇数次,其他的数都出现了偶数次,打印这两个数。

进阶思路:先将数组所有数字异或,最后结果就是两个出现一次的数字相互异或的结果,再将这两个数分别分在两个数组中进行异或。

 

https://www.cnblogs.com/Lee-yl/p/9123793.html

6、在其他数都出现K次的数组中找到只出现一次的数

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

思路:时间O(N),空间O(1)

定律:k个相同的k进制无进位相加的结果为0.
例如: 两个相同的2进制 100110101
100110101
无进位相加 结果 0000000

解法:把数组中的每个元素看成k进制 , 所有元素相加后得到的k进制结果就是 那个只出现一次的数,然后转成相应的十进制,得解。

详细解释:

一个重要结论:

解该题:

代码:

 

def onceNum(arr,k):
    eO = [0] * 32
    for i in range(len(arr)):
        setExclusiveOr(eO,arr[i],k)
    res = getNumFromKSysNum(eO,k)
    return res
#获得所有的K进制无进位加和
def setExclusiveOr(eO,value,k):
    curKSysNum = getKSysNumFromNum(value,k)
    for i in range(len(eO)):
        eO[i] = (eO[i] + curKSysNum[i]) % k
#获得K进制,res返回的是k进制
def getKSysNumFromNum(value,k):
    res = [0] * 32
    index = 0
    while value != 0:
        res[index] = value % k
        index += 1
        value = value // k
    return res

#将结果的那个K进制数转成十进制数输出
def getNumFromKSysNum(eO,k): res = 0 for i in range(len(eO) - 1,-1,-1): res = res * k + eO[i] return res arr = [1,1,1,2,2,2,4] k = 3 onceNum(arr,k)

 

 

7、请设置一种加密过程,完成对明文text的加密和解密工作。

 

8、数的幂

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

思路:

写出指数的二进制表达,例如13表达为二进制1101。 通过&1和>>1来逐位读取1101,为1时将该位代表的乘数累乘到最终结果。

 举例:10^1101 = 10^0001*10^0100*10^1000

代码:

    def Power(self, base, exponent):
        # write code here
        #return math.pow(base,exponent)
        
        if base == 0 :
            return 0
        if exponent == 0:
            return 1
        elif exponent < 0:
            n = -exponent
        else:
            n = exponent
        res = 1
        cur = base
        while n:
            if (n&1) == 1:
                res *= cur
            cur *= cur
            n = n >> 1
        return res if exponent > 0 else (1/res)

 

转载于:https://www.cnblogs.com/Lee-yl/p/9588361.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值