位运算 笔记

这几天撸了一下位运算。
写个笔记总结一下。
首先运算了解一下。
& : 按位与
| : 按位或
^ : 按位异或
~ : 取反
<< : 左移 >> : 右移

位运算有些非常奇妙,我目前只学了一点点…路还长呢。
首先举个例子
无限大 大一的时候在c语言平时会用1000000这样写 ,但是是不严谨的。它无法代表整型的最大。
之后我学会了用(~(0x1<<31) 或者0x7fffffff 这样就可以,有时要预防溢出
又比如以前判断奇偶会这样写 x % 2 == 0。
但是后来我会这样写 (x&1) == 0.
还有交换两个数,以前是这样写的 t = a; a= b; b = t;
现在直接宏定义 #define(a, b) (a^=b, b^=a, a^=b)
然后了解几个例子。
比如说吧,如何去除一个数 x二进制最后一个1
是这样的(x&(x - 1)) 不了解的可以手写一下然后看下结果。
有了这样的概念,对于力扣231这一题
231. 2的幂
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
示例 1:
输入: 1
输出: true
解释: 20 = 1
示例 2:
输入: 16
输出: true
解释: 24 = 16
示例 3:
输入: 218
输出: false
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/power-of-two
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

这一题,我们本来可以不停除2,看最后是否等于1
但是掌握了上面我们说的思想以后。
就直接简单了。只需要两行代码。

class Solution {
    public boolean isPowerOfTwo(int n) {
        if(n <= 0) return false;
        return (n & (n - 1)) == 0;
            
    }
}

因为如果是2的幂 那么它的二进制必定只有一个1.
去掉了最后一个1,那么就只能是0了。

这还不够奇妙的话,再看一题升级版。
342. 4的幂
给定一个整数 (32 位有符号整数),请编写一个函数来判断它是否是 4 的幂次方。
示例 1:
输入: 16
输出: true
示例 2:
输入: 5
输出: false
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/power-of-four
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

不同于上一题,这是4的幂。
那么观察一下,4的幂也只有1个1,但是每一个1都必定在二进制的奇数位上。
偶数位必须是0.
那么我给你一个数。
1010101010101010101010101010101
这个数严格满足了上面的条件。
那么将一个4的幂的数,与这个数,按位与。会怎么样?
答案是不会怎么样。
我们称4的幂为x,x的二进制只有一个1,并且在奇数位。这个数所有的奇数位都是1,而偶数位都是0,那么两数经过&, 1&1还是1,0&0还是0,1&0还是0,所以根本不会变化。
反之 如果它不是4的幂,如果是2的幂 那么在偶数上是1,但是那个数的偶数上是0,即1&0为0
则变化了,不再是原来那个数。
所以与1010101010101010101010101010101经过按位与而不变的数,一定是4的幂。
1010101010101010101010101010101的16进制写法为0x55555555。

class Solution {
    public boolean isPowerOfFour(int num) {
        if(num <= 0) return false;
        if((num & num - 1) != 0) return false;
        return (num & 0x55555555) == num;
    }
}

再看这题
268. 缺失数字
给定一个包含 0, 1, 2, …, n 中 n 个数的序列,找出 0 … n 中没有出现在序列中的那个数。
示例 1:
输入: [3,0,1]
输出: 2
示例 2:
输入: [9,6,4,2,3,5,7,0,1]
输出: 8
说明:
你的算法应具有线性时间复杂度。你能否仅使用额外常数空间来实现?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/missing-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

要求线性。

int missingNumber(int* nums, int numsSize){
    int visited[numsSize + 1];
	memset(visited, 0, sizeof(visited));
	int i, j;
	for(i = 0; i < numsSize; i ++) {
		visited[nums[i]] = 1;
	}
	for(i = 0; i < numsSize; i ++) {
		if(visited[i] == 0) {
			break;
        }
	}
    return i;
}

以前我是这么写的。
ac了。效率可以说还不错。
现在可以用异或

class Solution {
    public int missingNumber(int[] nums) {
        int res = 0;
        for(int i = 0; i <= nums.length; i ++)
            res ^= i;
         for(int num : nums)
            res ^= num;
        return res;
    }
}

当然还有高斯求和公式的数学解法。更妙。
我复制了官解。

class Solution {
    public int missingNumber(int[] nums) {
        int expectedSum = nums.length*(nums.length + 1)/2;
        int actualSum = 0;
        for (int num : nums) actualSum += num;
        return expectedSum - actualSum;
    }
}

作者:LeetCode
链接:https://leetcode-cn.com/problems/missing-number/solution/que-shi-shu-zi-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

类似的一题。
389. 找不同
给定两个字符串 s 和 t,它们只包含小写字母。
字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。
请找出在 t 中被添加的字母。

示例:
输入:
s = “abcd”
t = “abcde”
输出:
e
解释:
‘e’ 是那个被添加的字母。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-the-difference
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

直接异或刚起来。
学习了评论区大神的写法。

class Solution {
    public char findTheDifference(String s, String t) {
        int res = 0;
        for(Character x : s.toCharArray()) {
            res ^= x;
        }
        for(Character x : t.toCharArray()) {
            res ^= x;
        }
        return (char) res;
    }
}

最后看一题,我觉得很不错的题目。
318. 最大单词长度乘积
给定一个字符串数组 words,找到 length(word[i]) * length(word[j]) 的最大值,并且这两个单词不含有公共字母。你可以认为每个单词只包含小写字母。如果不存在这样的两个单词,返回 0。
示例 1:
输入: [“abcw”,“baz”,“foo”,“bar”,“xtfn”,“abcdef”]
输出: 16
解释: 这两个单词为 “abcw”, “xtfn”。
示例 2:
输入: [“a”,“ab”,“abc”,“d”,“cd”,“bcd”,“abcd”]
输出: 4
解释: 这两个单词为 “ab”, “cd”。
示例 3:
输入: [“a”,“aa”,“aaa”,“aaaa”]
输出: 0
解释: 不存在这样的两个单词。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-product-of-word-lengths
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

如果不用位运算还真是有点麻烦。
那用位运算该怎么写呢?
因为题目规定必须没有公共字母。就可以很容易想到按位与&。
不同的字母按位与必须是0。相同则为0 .
那么可不可以这样表示。
“abc” 为 00000000 00000000 00000000 00000111.
"bc"为00000000 00000000 00000000 00000110.
"abcde"为00000000 00000000 00000000 00011111.
有就用1来表示。
那么abc & bc 必定是00000000 00000000 00000000 00000111
如果ab & c 就是00000000 00000000 00000000 00000000
无公共就是0.

题目就可以解决了。
参考自评论区大神。

class Solution {
    public int maxProduct(String[] words) {
        int[] a = new int[words.length];
        for(int i = 0; i < words.length; i ++) {
            int m = words[i].length();
            for(int j = 0; j < m; j ++) {
                a[i] |= 1 << (words[i].charAt(j) - 'a');
            }
        }
        int max = 0;
        for(int i = 0; i < words.length; i ++) {
            for(int j = i + 1; j < words.length; j ++) {
                if((a[i] & a[j]) == 0)
                    max = Math.max(words[i].length() * words[j].length(), max);
            }
        }
        return max;
    }
}

前路漫漫啊。还有很多需要去学习呢。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值