位移运算 1.0

这篇博客介绍了如何利用位运算在整型数组中快速找到出现奇数次的数。通过异或操作,可以将所有数出现的次数转换为奇数次的那个数。对于两种数出现奇数次的情况,通过位运算和提取最右侧的1来找到这两个数。此外,还展示了选择排序和归并排序的基本原理和实现。
摘要由CSDN通过智能技术生成

相同为0, 不同为 1
a^b
0 0 0
1 1 0
1 0 1
0 1 0

a 1 0 1 1 0
b 0 0 1 1 1
^ 1 0 0 0 1
还可以理解为 无进位相加 1+1 =0 1+0=1 0+0=0

性质:

  1. 0^ N= N
  2. N^N=0
  3. 满足交换律 结合律
  4. a ^ b =b ^ a
  5. (a ^b ) ^ c= a ^ (b ^ c)

示例:

int a= 甲 int b= 乙

a = a ^ b —> a=甲 ^ 乙 b=乙

b = a ^ b —> b=甲 ^ 乙 ^ 乙 = 甲 a=甲 ^ 乙

a = a ^ b —> a=甲 ^ 乙 ^ 甲= 乙 b=甲

a= 乙 b=甲

前提: a 和 b 是 内存独立的区域
a指向的内存 和 b 指向的内存 是不同的

在数组中, 使用 ^ 前提 是 i 位置不能等于 j位置

位与( & )
5转换为二进制:0000 0000 0000 0000 0000 0000 0000 0101

3转换为二进制:0000 0000 0000 0000 0000 0000 0000 0011


1转换为二进制:0000 0000 0000 0000 0000 0000 0000 0001

第一个操作数的的第n位于第二个操作数的第n位如果都是1,那么结果的第n为也为1,否则为0


位或( | )
5转换为二进制:0000 0000 0000 0000 0000 0000 0000 0101

3转换为二进制:0000 0000 0000 0000 0000 0000 0000 0011


7转换为二进制:0000 0000 0000 0000 0000 0000 0000 0111

第一个操作数的的第n位于第二个操作数的第n位 只要有一个是1,那么结果的第n为也为1,否则为0


在一个整形数组中,
1.已知 只有 一种数 出现了 奇数次 ,其他的 所有数都出现了 偶数次
如何找到 出现了 奇数次的数
2.已知 有两种数 出现了 奇数次 ,其他的数 都出现了 偶数次

时间复杂度 o(n) 空间复杂度 o (1)

解题1: int eor=0;
arr【2,3,1,2,1,3,3,1,1】

eor 分别 与 数组的每个数 使用 ^
由于 2为偶数 2个 最终为 0
由于 1为偶数 4个 最终为 0
由于 3为奇数3个 最终为 3

而 0 ^ 甲 = 甲

题解2:

一个数 提反 该数+1 提取出最右侧的 1

int rightOne= eor & (~eor +1) // 提取出最右侧的1

eor = 1 0 1 0 1 1 1 1 0 0
~eor= 0 1 0 1 0 0 0 0 1 1
~eor+1= 0 1 0 1 0 0 0 1 0 0

eor& (~eor+1) =
0 0 0 0 0 0 0 1 0 0

在这里插入图片描述

选择排序 进行 0-i次排序 每次 0-i的地方保持顺序
在这里插入图片描述
在这里插入图片描述

package com.ma.zuoSuanFa;
/*
在一个整形数组中,
1.已知 只有 一种数 出现了 奇数次  ,其他的 所有数都出现了 偶数次
如何找到 出现了 奇数次的数
2.已知 有两种数 出现了 奇数次 ,其他的数 都出现了 偶数次
 */
public class CodeSeven {
    public static void main(String[] args) {
        CodeSeven codeSeven=new CodeSeven();
        int[] s={2,3,1,2,1,3,3,1,1};
        codeSeven.getOneJi(s);

        int[] d={1,1,1,1,2,2,3,3,3,5,5,5};
        codeSeven.getTwo(d);

        codeSeven.fastsory(s);
    }

    private int[] fastsory(int[] d) {
        //首先进行 0-i次做到有序
        for (int i = 1; i < d.length; i++) {
            //0-0有序 0-i想有序
            for (int j=i-1 ; j>=0  && d[j] > d[j+1] ; j--){
                swapD(d,j,j+1);
            }
        }
        return d;
    }

    private void swapD(int[] d, int j, int i) {
        int n=d[j];
        d[j]=d[i];
        d[i]=n;
    }

    private void getTwo(int[] d) {
        //先求出eor=a ^ b
        int eor=0;
        for (int cur : d) {
            eor ^=cur;
        }
        //eor=a ^ b
        //eor !=0
        //eor 必然有一个位置上 是 1
        int rightOne= (eor) & (~eor +1);//求出最右侧的1

        int onlyOne=0;
        for (int cur : d) {
            if ( (rightOne & cur )==0 )
            {
                onlyOne ^=cur;
            }
        }
        System.out.println(onlyOne +" "+ (eor^onlyOne) );
    }

    /*
        解题1: int eor=0;
    arr【2,3,1,2,1,3,3,1,1】

    eor 分别 与 数组的每个数 使用  ^
    由于 2为偶数 2个 最终为 0
    由于 1为偶数 4个 最终为 0
    由于 3为奇数3个 最终为 3
    而 0 ^ 甲  = 甲
     */
    private int getOneJi(int[] s) {
        int eor=0;
        for (int i = 0; i <s.length ; i++) {
            eor=eor ^ s[i];
        }
        return eor;
    }
}


归并排序

package zuoSuanFa;
/*
    归并排序
 */
public class MegreTest {

    public static void main(String[] args) {
        MegreTest megreTest=new MegreTest();
        int[] arr={10,2,3,1,3,5,7,9,7,8,6};

        megreTest.process(arr,0,arr.length-1);
    }

    private void process(int[] arr, int L, int R) {
    if (L==R){
        return;
    }
    int mid = (R-L)/2 + L;
    process(arr,L,mid);
    process(arr,mid+1,R);
    merge(arr, L, mid, R);
    }

    private int[] merge(int[] arr, int L, int mid, int R) {
        int[] help=new int[R-L +1];
        int i=0;
        int p1=L;
        int p2=mid+1;
        while (p1 <= mid && p2 <= R )
        {
        help[i++] = arr[p1] <= arr[p2] ? arr[p1++]  : arr[p2++] ;
        }
        while (p1 <= mid){
            help[i++] =arr[p1++];
        }
        while (p2 <= R)
        {
            help[i++]=arr[p2++];
        }
        for (i = 0; i < help.length; i++) {
            arr[L+i] = help[i];
        }
        return arr;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值