LeetCode-位运算

137. 只出现一次的数字 II

在这里插入图片描述

思路
开辟一个32容量数组, 然后逐位计算个数 然后 % 3

public int singleNumber(int[] nums) {
        int[] bitTag = new int[32];
        for (int nm : nums) {
        	// 对每个数 计算bit位的值
        	
            for (int i = 0; i < 32; i++) {
                bitTag[i] += nm & 1;
                nm >>= 1;
            }
        }
        int ans = 0;
        for (int i = 0; i < 32; i++) {
            // 要先移位, 否则最后一个后多移位一次
            ans <<= 1;
            ans |= bitTag[31 - i] % 3;
            
        }
        return ans;
    }

260. 只出现一次的数字 III

在这里插入图片描述

思路
偶数个相同的数互相异或是0
两个不同的数异或必定有一位是不同的, 所以 从低位到高位开始判断哪位是1
因为其他的数都是偶数个, 那么根据这个来分为两组 进行互相异或

public int[] singleNumber(int[] nums) {
       int[] ans = new int[2];
        int temp = 0;
        for (int nm : nums) {
            temp ^= nm;
        }
        int i = 0;
        // 寻找分割点
        while ((temp & 1) == 0) {
            i++;
            temp >>= 1;
        }
        for (int nm : nums) {
            if ((nm & (1 << i)) == 0) {
                ans[0] ^= nm;
                continue;
            }
            ans[1] ^= nm;
        }
        return ans;     
    }

421. 数组中两个数的最大异或值

在这里插入图片描述

思路
两个数异或值最大 那么就尽可能的让异或后的位数1足够多
构造一个前缀树 进行遍历寻找
在遍历的时候, 如果当前位是1, 那么就寻找0的前缀树路径
在这里插入图片描述

//节点
static class Node {
        Node one = null;
        Node zero = null;
    }
    // 构建前序树
    public static void BuildTree(Node root, int num) {
         int value = 0;
         for (int i = 31; i >= 0; i--) {
             value = (num >> i) & 1;
             if (value == 1) {
                 if (root.one == null) {
                     root.one = new Node();
                 }
                 root = root.one;
             } else {
                 if (root.zero == null) {
                     root.zero = new Node();
                 }
                 root = root.zero;
             }
         }
    }
    public  int findMaximumXOR(int[] nums) {
        Node root = new Node();
        for (int nm : nums) {
            BuildTree(root, nm);
        }
        int max = 0;
        int tempNum;
        int bitValue;
        Node temp;
        // 遍历每个数
        for (int nm : nums) {
            tempNum = 0;
            temp = root;
            for (int i = 31; i >= 0; i--) {
                bitValue = (nm >> i) & 1;
                // bit是1的时候, 就寻找 Node是0的 因为要异或和最大
                if (bitValue == 1) {
                    if (temp.zero != null) {
                        temp = temp.zero;
                        tempNum |= 1 << i;
                    } else {
                        temp = temp.one;
                    }
                } else {
                    if (temp.one != null) {
                        temp = temp.one;
                        tempNum |= 1 << i;
                    } else {
                        temp = temp.zero;
                    }
                }
            }
            max = Math.max(max, tempNum);
        }
        return max;
    }

318.最大单词长度乘积

在这里插入图片描述

思路
对每个字母计算后的位序进行 或 1 处理
如果两个String 每个字母都不同的话, 那么 进行 & 必定等于0
那么满足条件 计算长度积

public int maxProduct(String[] words) {
       int[] bitNums = new int[words.length];
       for (int i = 0; i < words.length; i++) {
           for (int j = 0; j < words[i].length(); j++) {
           	   // 对每个str的每个单词进行移位处理
               bitNums[i] |= 1 << (words[i].charAt(j) - 'a');
           }
       }
       int max = 0;
       for (int i = 0; i < words.length; i++) {
           for (int j = 1; j < words.length; j++) {
           		// 两个没有任何单词相同的进行 & 运算就是0
               if ((bitNums[i] & bitNums[j]) == 0) {
                   max = Math.max(max, words[i].length() * words[j].length());
               }
           }
       }
       return max;
    }

338. 比特位计数

在这里插入图片描述

/**
方法1:
递归: 偶数的1的个数和这个数/2是相同的, 例如  1000(8) == 100(4)
	  奇数的1的个数是上一个数+1,  101(5) = 100(4) + 1
*/
 public int[] countBits(int num) {
		int[] result = new int[num + 1];
		int[] bk = new int[num + 1];
		for (int i = 0; i <= num; i++) {
			result[i] = getCount(i, bk);
		}
		return result;
	}
	public int getCount(int num, int[] bk) {
		if (num == 0) return 0;
		if (bk[num] != 0) return bk[num];

		int result = 0;
		if (num % 2 == 0) {
			result = getCount(num / 2, bk);
		} else {
			result = getCount(num - 1, bk) + 1;
		}
		bk[num] = result;
		return result;
	}

/*
方法2: 计算每个数的1,并且用备忘录加速*/
public int[] countBits(int num) {
		int[] result = new int[num + 1];
		int[] bk = new int[num + 1];
		for (int i = 0; i <= num; i++) {
			result[i] = getCount(i, bk);
		}
		return  result;
	}
	public int getCount(int num, int[] bk) {
		int count = 0;
		int temp = num;
		while (temp > 0) {
			// 备忘录加速
            if (bk[temp] != 0) {
				count = bk[temp] + count;
				bk[num] = count;
				return count;
			}

			if ((temp & 1) > 0) {
				count++;
			}
			temp >>>= 1;
		}
		bk[num] = count;
		return count;
	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值