精华内容
下载资源
问答
  • I 数组中数字出现一次的数...当只有一个数字出现一次,其他数字出现两次的时候,可以将数组异或,然后可以得出出现一次的数字的值 两个数字出现一次的情况可以分解为两个数组,每个数组一个数字出现一次的情况 分组

    I 数组中数字出现一次的数

    个人博客


    一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

    输入:nums = [4,1,4,6]
    输出:[1,6] 或 [6,1]
    

    题解

    • 分组异或

      • 算法思想(异或运算符合交换律

        • 当只有一个数字出现一次,其他数字出现两次的时候,可以将数组异或,然后可以得出出现一次的数字的值

        • 两个数字出现一次的情况可以分解为两个数组,每个数组一个数字出现一次的情况

        • 分组异或

          • 将整个数组异或后的结果是一个不为 0 的数(因为两个出现一次的数字「计为 A、B」不可能是同一个数)
          • 不为 0 的数中所有的位「第n 位」肯定有一个为 1,这说明A、B 的第 n 为不相同,即一个为 1,一个为 0
          • 所以可以通过第 n 位为 1 或 0 将数组分为两个子数组,此时两次出现的数字一定会分在同一个组中,然后将两个组中的数字进行异或,就可以得到A、B
      • 复杂度分析

        • 时间复杂度 O(n)
        • 空间复杂度 O(1)
      class Solution {
          public int[] singleNumbers(int[] nums) {
              int xor = 0;
              for(int num:nums)xor ^= num;
              int mask = 1;
              while((xor & mask) == 0){
                  mask <<= 1;
              } 
              int a = 0,b = 0;
              for(int num: nums){
              		//注意,此处要为 0,当第 n 位与 mask 相同时可以得到一个结果,不为0,可能性很多,但是相同的						话,结果只能为 0
                  if((num & mask) == 0)a ^= num;
                  else b ^= num;
              }
              return new int[]{a,b};
          }
      }
      

    II 数组中数字出现的次数


    在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。

    输入:nums = [3,4,3,3]
    输出:4
    

    题解

    • 遍历统计

      • 算法思想
        • 将每个数字的每一位累加到一个长 32 的数组中
        • 然后将数组中的每一个元素取 3 的余数
        • 就可以得到出现一次的数在每一位上是 0 还是 1
      • 复杂度分析
        • 时间复杂度 O(n)
        • 空间复杂度 O(1):32 位的空间是固定的,算常数空间
      class Solution {
          public int singleNumber(int[] nums) {
              int[] sum = new int[32];
              for(int num:nums){
                  for(int i = 0;i < 32;i++){
                      sum[i] += num & 1;
                      num >>>= 1;
                  }
              }
              int res = 0;
              for(int i = 31; i >= 0;i--){
                  res <<= 1;
               		//与 0 或运算,sum[i]%3是 1 res 相应的位就是 1,然后左移,总共移动 31 次
                  res |= sum[i] % 3;            
              }
              return res;
          }
      }
      

    总结

    • 位运算很巧妙,总的来说还是记住

      • 出现一个一次,其余出现两次:异或运算

      • 两个出现一次,其余出现两次:根据整体异或结果分为两组,然后分组异或

      • 一个出现一次,其余出现三次:遍历统计数字的每一位,然后取 3 的余数,结果就是出现一次的数字相应位上的数字

    展开全文
  • 运算小结(按位与、按或、按位异或、取反、左移、右移)  运算主要包括按位与(&amp;)、按或(|)、按位异或(^)、取反(~)、左移(&lt;&lt;)、右移(&gt;&gt;)这几种,其中除了取反(~)以外...

    位运算小结(按位与、按位或、按位异或、取反、左移、右移)

         位运算主要包括按位与(&)、按位或(|)、按位异或(^)取反(~)左移(<<)右移(>>)这几种,其中除了取反(~)以外,其他的都是二目运算符,即要求运算符左右两侧均有一个运算量。

       1、补码

       在总结按位运算前,有必要先介绍下补码的知识,我们知道当将一个十进制正整数转换为二进制数的时候,只需要通过除2取余的方法即可,但是怎么将一个十进制的负整数转换为二进制数呢?其实,负数是以补码的形式表示,其转换方式,简单的一句话就是:先按正数转换,然后取反加1。    

    10转为-10,原码取反,加一

    要将十进制的-10用二进制表示,先将10用二进制表示:

    0000 0000 0000 1010

    取反:

    1111 1111 1111 0101

    加1:

    1111 1111 1111 0110

    所以,-10的二进制表示就是:1111 1111 1111 0110

       

    2、按位与(&)   ---  都是一,才为一

       参加运算的两个数,换算为二进制(0、1)后,进行与运算。只有当相应位上的数都是1时,该位才取1,否则该位为0。

    将10与-10进行按位与(&)运算:

    0000 0000 0000 1010

    1111 1111 1111 0110

    -----------------------

    0000 0000 0000 0010

    所以:10 & -10 = 0000 0000 0000 0010

       

    3、按位或(|) ---  有1,就为1

       参加运算的两个数,换算为二进制(0、1)后,进行或运算。只要相应位上存在1,那么该位就取1,均不为1,即为0。

    将10与-10进行按位或(|)运算:

    0000 0000 0000 1010

    1111 1111 1111 0110

    -----------------------

    1111 1111 1111 1110

    所以:10 | -10 = 1111 1111 1111 1110

     

       4、按位异或(^)  -- 都是1,就是0

       参加运算的两个数,换算为二进制(0、1)后,进行异或运算。只有当相应位上的数字不相同时,该为才取1,若相同,即为0。

    将10与-10进行按位异或(^)运算:

    0000 0000 0000 1010

    1111 1111 1111 0110

    -----------------------

    1111 1111 1111 1100

    所以:10 ^ -10 = 1111 1111 1111 1100

       可以看出,任何数与0异或,结果都是其本身。利用异或还可以实现一个很好的交换算法,用于交换两个数,算法如下:

    a = a ^ b;

    b = b ^ a;

    a = a ^ b;

     

     5、取反(~)

       参加运算的两个数,换算为二进制(0、1)后,进行取反运算。每个位上都取相反值,1变成0,0变成1。

    对10进行取反(~)运算:

    0000 0000 0000 1010

    ---------------------

    1111 1111 1111 0101

    所以:~10 = 1111 1111 1111 0101

       6、左移(<<)

       参加运算的两个数,换算为二进制(0、1)后,进行左移运算,用来将一个数各二进制位全部向左移动若干位。

    对10左移2位(就相当于在右边加2个0):

    0000 0000 0000 1010

    --------------------

    0000 0000 0010 1000  

    所以:10 << 2 = 0000 0000 0010 1000 = 40

       注意,观察可以发现,左移一位的结果就是原值乘2,左移两位的结果就是原值乘4

       7、右移(>>)

       参加运算的两个数,换算为二进制(0、1)后,进行右移运算,用来将一个数各二进制位全部向右移动若干位。

    对10右移2位(就相当于在左边加2个0):

    0000 0000 0000 1010

    --------------------

    0000 0000 0000 0010

    所以:10 >> 2 = 0000 0000 0000 0010 = 2

       注意,观察可以发现,右移一位的结果就是原值除2,左移两位的结果就是原值除4,注意哦,除了以后没有小数位的,都是取整。

    展开全文
  • 运算符的计算 按位与运算符 [ & ] 按或运算符 [ | ] 异或运算符 [ ^ ] 取反运算符 [ ~ ] 计算机原码、反码、补码 机器数 真数 原码 反码 补码 有了原码为什么要使用反码补码

    参考:运算符的计算(按位与 按位或 异或 取反)
    作者:一只青木呀
    发布时间: 2020-07-23 18:13:55
    网址:https://blog.csdn.net/weixin_45309916/article/details/107543919

    参考:计算机原码,反码,补码
    作者:chenchao2017
    发布时间: 2018-04-03 10:22:38
    网址:https://blog.csdn.net/chenchao2017/article/details/79733278?utm_medium=distribute.pc_relevant_t0.none-task-blog-searchFromBaidu-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-searchFromBaidu-1.control

    位运算

    按位与运算符 [ & ]

    运算规则:依次比较两个二进制数的每一位,全部为1则为1,否则为0的规则,依次计算出一个新的二进制数:

    即:0 & 0= 0 ,0 & 1= 0,1 & 0= 0, 1 & 1= 1
    例: 39 & 21 --> 0010 0111 & 0001 0101 --> 0000 0101

    按位或运算符 [ | ]

    运算规则:依次比较两个二进制数的每一位,只要有一个为1则为1,否则为0的规则,依次计算出一个新的二进制数:

    即:0 | 0= 0 ,0 | 1= 1,1 | 0= 1, 1 | 1= 1
    例: 39 | 21 --> 0010 0111 | 0001 0101 --> 0011 0111

    异或运算符 [ ^ ]

    运算规则:依次比较两个二进制数的每一位,按照相同为0,不同为1的规则,依次计算出一个新的二进制数:

    即:0 ^ 0= 0 ,0 ^ 1= 1,1 ^ 0= 1, 1 ^ 1= 1
    例: 39 ^ 21 --> 0010 0111 ^ 0001 0101 --> 0011 0010

    取反运算符 [ ~ ]

    运算规则:对于二进制数的每一位,1变0,0变1,得到一个新的二进制数:

    即:~0 = 1 , ~1= 0
    因为涉及到、补码、原码、符号,感觉挺复杂的,涉及的知识比较多,总结为一句:

    对所有整数取反=本身的相反数减一
    ~9 = -10
    ~10 = -11

    移位操作

    <<: 左移、>> : 右移
    箭头指向哪就是向哪移。左移之后右边补0,右移之后在左边补0

    结论: 对于正数而言,其实左移和右移n位就相当于乘以或者除以2的n次方。

    比如:十进制的5,该数二进制为 0000 0101,将该数左移3为
    结果为0010 1000,转换成十进制为 40, 验证了上面的结论:5左移三位就等于5乘以2的三次方等于40。
    再比如:十进制的40,右移三位就相当于除以8(2的三次方)结果为5。
    那么问题来了,有一个数a,有一个数b,我要让b等于a的第三位,怎么算。

    思路:先让a右移俩位,那么a原来的第三位现在就变成最后一位,再让移后的数和1想与,结果即为a原来的第三位。

    一些面试常考的位操作运算

    去掉最后一位 | (101101->10110) | 				x >> 1
    在最后加一个0 | (101101->1011010) | 				x << 1
    在最后加一个1 | (101101->1011011) |				x << 1+1
    把最后一位变成1 | (101100->101101) | 			x | 1
    把最后一位变成0 | (101101->101100) | 			x | 1-1
    最后一位取反 | (101101->101100) | 				x ^ 1
    把右数第k位变成1 | (101001->101101,k=3) | 		x | (1 << (k-1))
    把右数第k位变成0 | (101101->101001,k=3) | 		x & ~ (1 << (k-1))
    右数第k位取反 | (101001->101101,k=3) | 			x ^ (1 << (k-1))
    取末三位 | (1101101->101) | 						x & 7
    取末k位 | (1101101->1101,k=5) | 				x & ((1 << k)-1)
    取右数第k位 | (1101101->1,k=4) | 				x >> (k-1) & 1
    把末k位变成1 | (101001->101111,k=4) | 			x | (1 << k-1)
    末k位取反 | (101001->100110,k=4) | 				x ^ (1 << k-1)
    把右边连续的1变成0 | (100101111->100100000) | 	x & (x+1)
    把右起第一个0变成1 | (100101111->100111111) | 	x | (x+1)
    把右边连续的0变成1 | (11011000->11011111) |   	x | (x-1)
    取右边连续的1 | (100101111->1111) | 				(x ^ (x+1)) >> 1
    去掉右起第一个1的左边 | (100101000->1000) |   	x & (x ^ (x-1))
    判断奇数 										(x&1)==1
    判断偶数 										(x&1)==0 
    取右边第一个1所在位置 							x&-x
    

    计算机原码、反码、补码

    机器数

    一个数在计算机中的表现形式叫做机器数,这个数有正负之分,在计算机中用一个数的最高位(符号位)用来表示它的正负,其中0表示正数,1表示负数。

    例如正数7,在计算机中用一个8位的二进制数来表示,是00000111,而负数-7,则用10000111表示,这里的00000111和10000111是机器数

    在这里插入图片描述

    真数

    计算机中的机器数对应的真实的值就是真数,对最高位(符号位)后面的二进制数转换成10进制,并根据最高位来确定这个数的正负。对于上面的00000111和10000111来说,对最高位后面的二进制数转换成10进制是7,在结合最高位的值,得出对应的真数分别是7和-7

    原码

    用第一位表示符号,其余位表示值。因为第一位是符号位,所以8位二进制数的取值范围就是:[1111_1111 , 0111_1111] 即 [-127 , 127] ,原码是容易被人脑所理解的表达方式

    反码

    正数的补码反码是其本身,负数的反码是符号位保持不变,其余位取反。例如正数1的原码是[0000_0001],它的反码是是其本身

    [0000_0001],-1的原码是[1000_0001],其反码是[1111_1110]

    补码

    正数的补码是其本身,负数的补码是在其反码的基础上+1,例如正数1的原码是[0000_0001],他的补码是其本身[0000_0001],

    -1的补码是[1111_1111]

    有了原码为什么要使用反码和补码

    因为人脑可以知道第一位是符号位,可以根据符号位对真值的绝对值进行加减乘除,但是对于计算机来说,加减乘除是最最最基本的运算,要设计的尽量简单,计算机辨别符号位会让计算机的设计电路变得很复杂,于是人们想出了让符号位也参与到运算上来。减去一个数,等于加上他的负数

    使用原码参数运算的缺陷
    在这里插入图片描述
    从上面的原码表中可以看见左边每增加一个二进制单位对应的真数是递减的,而右边每增加一个二进制单位对应的真数是递增的,所以对于原码来说,能满足正数的加法,但无法满足负数的加法

    2+1 = [0000_0010]原+[0000_0001]原=[0000_0011]原 = 3

    1±1=[0000_00001]原+[1000_0001]原=[1000_0010]原=-2

    为了满足负数对加法的需求,就必须让负数与他对应的二进制码是同步递增或者同步递减

    于是就通过符号位不变,其余位取反来满足这个同步递增或者递减的要求,由于正数本来就满足它本身的加法,所以不需要做任何改变。这就是反码的定义由来。
    在这里插入图片描述
    从上图的反码表中可以看到在运算不跨过0的时候,正负数的加法已经能满足要求

    -2+1=[1111_1101]反+[0000_0001]反=[1111_1110]反=-1

    127+1=[1000_0000]反=-127=128 加法算出来是128,由于128超过最大值,余1,所以取最小值开始的第一位,也就是

    最小值-127,但是这里有个不合理的地方,就是[1111_1111]和[0000_0000]都表示0,这导致在实际计算中每当跨过0一次,就有一个单位的误差

    -1+2=[1111_1110]反+[0000_0010]反=[0000_0000]反=0

    要解决这个问题就必须让反码中的[1111_1111]和[0000_0000]合并,

    由于[1111_1111]+[0000_0001]=[0000_0000],所以在负数反码的基础上+1就可以解决反码中跨0的误差问题,同时不会对负数与它对应的二进制反码的同步递增产生影响,所以在反码的基础上+1就完美的解决了符号参与预算的问题,这就是补码为什么是在负数反码的基础上+1的由来。
    在这里插入图片描述
    从上面的图中发现还有一个[1000_0000]的二进制没有对应任何真数,于是就规定了这个数的真数是-128

    所以补码的表示范围是[-128~127] ,这样一来256个二进制正好表示256个整数,在实际二进制的运算中超过范围其实就是对256的取余预算(x+128)mod 256 - 128。

    展开全文
  • 异或的应用场景

    2019-09-13 15:48:05
    Java hashMap 中的实现用的了巧妙的避开了除法取余的效率问题,可查阅相关资料。 判断两个字符串是否为子串也可以用或跟来解决。 ^ 的应用(交换值) 找出重复数 解法: ...
    & 的应用(权限值)(可以放便的进行权限值判断)
    2^0=1, 相应 2 进制为 "0001" (在这里 ^ 我表示成"次方", 即: 2 的 0 次方, 下同)
    2^1=2, 相应 2 进制为 "0010"
    2^2=4, 相应 2 进制为 "0100"
    2^3=8, 相应 2 进制为 "1000"
    ...

    要判断一个数在某些数范围内就可以使用 & 运算符(数值从上面的表中得来)
    如: 7=4|2|1 (你也可以简单理解成 7=4+2+1)
    用 & 来操作,可以知道 7&6、7&5、7&4、7&3 、7&2、7&1 都是真的,而如果 7&8 则是假的
    判断权限使用 & (是, 返回非 0; 不是, 返回 0)

    Java hashMap 中的实现用的了与巧妙的避开了除法取余的效率问题,可查阅相关资料。
    判断两个字符串是否为子串也可以用或跟与来解决。

    ^ 的应用(交换值)
    找出重复数
    解法: 全部异或

    转载于:https://my.oschina.net/taisha/blog/59015

    展开全文
  • 文件指针偏移, rewind函数,ftell函数 , fseek函数操作操作逻辑操作数据的二进制表示二进制打印位与(&)按或(|)取反(~)位异或(^)左移(<...逻辑操作的世界里,只有真假(零非零),而操作的世...
  • 运算应用口诀 ...清零取反要用,某位置一可用...若要取反交换,轻 轻松松用异或 移位运算 要点 1 它们都是双目运算符,两个运算分量都是整形,结果也是整形。  &nb...
  • 异或^规律总结

    千次阅读 2021-03-06 16:57:31
    我们知道,异或是通过比较二进制的值,相同0,不同为1,根据此特性,我们可以发现以下规律: 结合律 (a ^ b) ^ c = a ^ (b ^ c); 交换律 a ^ b = b ^ a; 对于一个数a来说: 异或自己的结果为0:a ^ a = 0; ...
  • 提及运算,相信对绝大多数Java程序员是感觉既陌生又熟悉的。陌生是因为你大概率没有去真实的使用过,熟悉是有时在看些开源框架(或者JDK源码)时会时长看到有使用的地方(譬如Jackson/Fastjson这些JSON库都大量的...
  • 运算总结取模取余

    2017-05-28 00:14:58
    运算总结取模取余tags:运算总结via:http://blog.csdn.net/black_ox/article/details/46411997Summary: 运算应用口诀 清零取反要用,某位置一可用或 若要取反交换,轻 轻松松用异或 移位运算 要点 1 它们都是...
  • 前言 今天想加一个QQ群,进群需要回答问题,刚看到这个问题一脸懵逼,群主有点东西哦?...最后猜应该是运算里面的或运算,填了15通过申请啦~所以把运算相关的知识点梳理一下。 正文 ...
  • 运算、取余取模

    2019-09-25 03:12:58
    l 取余和取模的共同点区别 对于整数: 相同:无论取余还是取模都分两步:1)求整数商:c=a/b 2)计算模或余数:r=a-c*b 不同:取模在计算c值时,向0方向舍入(fix()函数) 取余计算c时,向负无穷方向舍入...
  • C# 深入理解按位异或运算符

    千次阅读 2018-01-22 11:22:18
    例如对数10100001的第2位和第3位翻转,则可以将该数00000110进行按位异或运算。  10100001^00000110 = 10100111 (2) 实现两个值的交换,而不必使用临时变量。 例如交换两个整数a=10100001,b=00000110的...
  • 1^1=0例 如:10100001^00010001=101100000^0=0,0^1=1 0异或任何数=任何数1^0=1,1^1=0 1异或任何数-任何数取反任何数异或自己=把自己置0(1)按位异或可以用来使某些特定的位翻 转,如对数10100001的第2位和第3位...
  • 异或运算

    2020-08-04 09:01:18
    1..2^5 32 二进制 100000 2.的n次方的二进制就是1后面加n个0 3. 移位运算移走的那些二进制就是余数 ...6. 一个数15进行运算(二进制为0000 1111),就可以取到该数的低4。 7. 8. 9. 10. ...
  • 异或(xor,运算符号^):按计算,同0异1,1 ^ 0 = 1 ,1 ^ 1 = 0 ,如此。 现定义等差数列 1, 2, ... , n 的 异或和 为 f(n) = 1 ^ 2 ^ ... ^ n ,求f(n)的值。 实现 我们很容易想到质朴的实现如下: int func...
  • )按位与运算符(&)按或运算符(|)异或运算符( ^ 、xor ) 左移运算符( << ) 将该数的二进位进行左移,右补0。左移几相当于乘几次2;(看箭头的指向往左就是左移) 例:a<<1,即将a的二...
  • 使用异或交换两整数###运算判断奇偶 1.异或运算进行交换(只能是整型) 异或运算有两个特点: (1)一个数异或本身恒等于0;(2)一个数异或0恒等于本身。 function swap(a, b) { a = a ^ b; // 以a为临时变量 b...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 13,474
精华内容 5,389
关键字:

与和异或位取余