题目
给定两个整数 a 和 b ,求它们的除法的商 a/b ,要求不得使用乘号 ‘*’、除号 ‘/’ 以及求余符号 ‘%’ 。
注意:
整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231−1]。本题中,如果除法结果溢出,则返回 231 − 1
示例 1:
输入:a = 15, b = 2 输出:7
解释:15/2 = truncate(7.5) = 7
示例 2:
输入:a = 7, b = -3 输出:-2
解释:7/-3 truncate(-2.33333…) = -2
示例 3:
输入:a = 0, b = 1 输出:0
示例 4:
输入:a = 1, b = 1 输出:1
提示:
-231 <= a, b <= 231 - 1 b != 0
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/xoh6Oh
分析
由于题目中不允许使用除法,一般像这种问题我们要考虑使用二进制,假设我们有a=15, b=2,我们可以用减法来统计
a-b | |
---|---|
减0次 | 15 |
减1次 | 13 |
减2次 | 11 |
减3次 | 9 |
减4次 | 7 |
减5次 | 5 |
减6次 | 3 |
减7次 | 1 |
减到第7次a已经小于b了,此时不能再减,所以答案是7
但是这样会超时,我们接下来进行优化
a - n * b | ans | |
---|---|---|
减0次 | 15 | 0 |
减7次 | 15 - 7 * 2 | 7 |
这样能够马上得出答案,但是题目中要求不能使用乘号,在二进制中左移可以达到乘二的效果
n | a-b*(1<ans |
| |
---|---|---|---|
相当于减4次 | 2 | 15-2*(1<<2)=7 | 1<<2=4 |
相当于减2次 | 1 | 7-2*(1<<1)=3 | 4+(1<<1)=6 |
相当于减1次 | 0 | 3-2*(1<<0)=1 | 6+(1<<0)=7 |
代码
class Solution {
public:
int divide(int a, int b) {
if (a == INT_MIN && b == -1) return INT_MAX;
int sign = (a > 0) ^ (b > 0) ? -1 : 1;
unsigned int ua = abs(a);
unsigned int ub = abs(b);
unsigned int res = 0;
for (int i = 31; i >= 0; i--) {
if ((ua >> i) >= ub) {
ua = ua - (ub << i);
res += 1 << i;
}
}
return sign == 1 ? res : -res;
}
};
给定两个 01 字符串 a 和 b ,请计算它们的和,并以二进制字符串的形式输出。
输入为 非空 字符串且只包含数字 1 和 0。
示例 1:
输入: a = “11”, b = “10” 输出: “101”
示例 2:
输入: a = “1010”, b = “1011” 输出: “10101”
提示:
每个字符串仅由字符 ‘0’ 或 ‘1’ 组成。 1 <= a.length, b.length <= 10^4 字符串如果不是 “0” ,就都不含前导零。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/JFETK5
代码
class Solution {
public:
string addBinary(string a, string b) {
if(a.size() < b.size()){
string tmp = a;
a = b;
b = tmp;
}
int cur=0;
int al=a.size()-1, bl=b.size()-1;
while(bl >= 0){
int tmp = cur + a[al]-'0' + b[bl]-'0';
a[al] = tmp % 2 + '0';
cur = tmp / 2;
al--;
bl--;
}
while(cur && al >= 0){
int tmp = cur + a[al]-'0';
a[al] = tmp % 2 + '0';
cur= tmp / 2;
al--;
}
if(cur){
return '1' + a;
}
return a;
}
};
给定一个非负整数 n ,请计算 0 到 n 之间的每个数字的二进制表示中 1 的个数,并输出一个数组。
示例 1:
输入: n = 2
输出: [0,1,1]
解释:
0 --> 0
1 --> 1
2 --> 10
示例 2:
输入: n = 5
输出: [0,1,1,2,1,2]
解释:
0 --> 0
1 --> 1
2 --> 10
3 --> 11
4 --> 100
5 --> 101
说明 :
0 <= n <= 105
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/w3tCBm
代码
class Solution {
public:
vector<int> countBits(int n) {
vector<int> ans;
for(int i=0; i <= n; i++){
int t=i, cnt=0;
while(t){
t &= (t-1);
cnt++;
}
ans.push_back(cnt);
}
return ans;
}
};
给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。
示例 1:
输入:nums = [2,2,3,2]
输出:3
示例 2:
输入:nums = [0,1,0,1,0,1,100]
输出:100
提示:
1 <= nums.length <= 3 * 104
-231 <= nums[i] <= 231 - 1 nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/WGki4K
分析
方法1:我们可以遍历每一位1的个数,如果二进制位之和是3的倍数说明出现了三次,即我们要找的答案中这一位为0,否则答案这一位为1
方法2:通过方法1我们可以得出状态有三种:即对3取余,余数为0,1, 2,我们可以用两位二进制表示这三种状态,这里我们用a和b表示两位状态,x为当前的数
a_i | b_i | x_i | 新的a_i | 新的b_i |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 1 |
0 | 1 | 0 | 0 | 1 |
0 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 0 |
1 | 0 | 0 | 0 | 0 |
根据真值表我们可以写出逻辑表达式
a = a b ′ x ′ + a ′ b x b = a ′ b ′ x + a ′ b x ′ = a ′ ( b ⨁ a ) a=ab'x'+a'bx \\b=a'b'x+a'bx'=a'(b\bigoplus a) a=ab′x′+a′bxb=a′b′x+a′bx′=a′(b⨁a)
由于数字出现的次数只能是1或3,导致状态只能是0或1,并且状态为1时该位数位在答案中,那么我们可以直接返回b作为答案
方法1代码
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ans=0;
for(int i=0; i < 32; i++){
int cnt=0;
for(auto & n:nums){
cnt += (n>>i & 1);
}
if(cnt % 3){
ans |= (1<<i);
}
}
return ans;
}
};
方法2代码
class Solution {
public:
int singleNumber(vector<int>& nums) {
int a=0, b=0;
for(auto & n:nums){
int ta, tb;
ta = (~a & b & n)|(a & ~b & ~n);
tb = ~a & (b ^ n);
a = ta;
b= tb;
}
return b;
}
};
给定一个字符串数组 words,请计算当两个字符串 words[i] 和 words[j] 不包含相同字符时,它们长度的乘积的最大值。假设字符串中只包含英语的小写字母。如果没有不包含相同字符的一对字符串,返回 0。
示例 1:
输入: words = [“abcw”,“baz”,“foo”,“bar”,“fxyz”,“abcdef”]
输出: 16
解释: 这两个单词为 “abcw”, “fxyz”。它们不包含相同字符,且长度的乘积最大。
示例 2:
输入: words = [“a”,“ab”,“abc”,“d”,“cd”,“bcd”,“abcd”]
输出: 4
解释: 这两个单词为 “ab”, “cd”。
示例 3:
输入: words = [“a”,“aa”,“aaa”,“aaaa”]
输出: 0
解释: 不存在这样的两个单词。
提示:
2 <= words.length <= 1000
1 <= words[i].length <= 1000
words[i]仅包含小写字母
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/aseY1I
分析
我们可以将字符串中含有的字母用二进制表示,如果两个字符串存在相同的字母那么他们做与运算结果不为0,如果不存在相同字母与运算结果为0。
还可以通过对字符串从大到小排序进行优化,这样一旦找出符合就可以返回,虽然时间复杂度不会变,但是实际实际会减少。
代码
class Solution {
public:
int maxProduct(vector<string>& words) {
vector<int> v;
for(auto & w:words){
int t=0;
for(int i=0; i < w.size(); i++){
t |= (1<<(w[i]-'a'));
}
v.push_back(t);
}
int ans = 0;
for(int i=0; i < words.size()-1; i++){
for(int j=i+1; j < words.size(); j++){
if((v[i] & v[j]) == 0){
if(ans < words[i].size() * words[j].size()){
ans = words[i].size() * words[j].size();
}
}
}
}
return ans;
}
};
题目
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为 汉明重量).)。
提示:
请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
在 Java 中,编译器使用 二进制补码 记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。
示例 1:
输入:n = 11 (控制台输入 00000000000000000000000000001011)
输出:3 解释:输入的二进制串
00000000000000000000000000001011 中,共有三位为 ‘1’。
示例 2:
输入:n = 128 (控制台输入 00000000000000000000000010000000)
输出:1 解释:输入的二进制串
00000000000000000000000010000000 中,共有一位为 ‘1’。
示例 3:
输入:n = 4294967293 (控制台输入 11111111111111111111111111111101,部分语言中 n =-3)
输出:31 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 ‘1’。
提示:
输入必须是长度为 32 的 二进制串 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/er-jin-zhi-zhong-1de-ge-shu-lcof
代码
class Solution {
public:
int hammingWeight(uint32_t n) {
int cnt=0;
while(n){
cnt += (n & 1);
n >>= 1;
}
return cnt;
}
};
题目
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。
示例 1:
输入:x = 2.00000, n = 10
输出:1024.00000
示例 2:
输入:x = 2.10000, n = 3
输出:9.26100
示例 3:
输入:x = 2.00000, n = -2
输出:0.25000 解释:2-2 = 1/22 = 1/4 = 0.25
提示:
-100.0 < x < 100.0
-231 <= n <= 231-1
-104 <= xn <= 104
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof
代码
class Solution {
public:
double myPow(double x, int n) {
if(n == 0 || x == 1){
return 1;
}
long long p = n;
if(n < 0){
x = 1.0 / x;
p = -p;
}
double ans=1;
while(p){
if(p & 1){
ans *= x;
}
x *= x;
p >>= 1;
}
return ans;
}
};
题目
求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
示例 1:
输入: n = 3 输出: 6
示例 2:
输入: n = 9 输出: 45
限制:
1 <= n <= 10000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/qiu-12n-lcof
分析
我们都知道求和公式为n(n+1)/2,但是我们在这里不能使用乘除法,我们可以考虑使用位运算的快速乘来实现乘法,使用位运算的右移来实现除2。但是快速乘需要借助循环来实现,所以我们可以将循环拆开
由 2 13 = 8192 < 10000 < 16384 = 2 14 得 由2 ^{13}=8192<10000< 16384=2^{14}得 由213=8192<10000<16384=214得
最多循环14次,所以我们拆成14个条件即可
快速乘代码
#include
using namespace std;
int main(){
int a, b, ans=0;
cin>>a>>b;
while(b){
if(b & 1){
ans += a;
}
a <<= 1;
b >>= 1;
}
cout<<ans<<endl;
}
题目代码
class Solution {
public:
int sumNums(int n) {
int a=n, b=n+1;
int ans=0;
(b & 1) && (ans += a);
a <<= 1;
b >>= 1;
(b & 1) && (ans += a);
a <<= 1;
b >>= 1;
(b & 1) && (ans += a);
a <<= 1;
b >>= 1;
(b & 1) && (ans += a);
a <<= 1;
b >>= 1;
(b & 1) && (ans += a);
a <<= 1;
b >>= 1;
(b & 1) && (ans += a);
a <<= 1;
b >>= 1;
(b & 1) && (ans += a);
a <<= 1;
b >>= 1;
(b & 1) && (ans += a);
a <<= 1;
b >>= 1;
(b & 1) && (ans += a);
a <<= 1;
b >>= 1;
(b & 1) && (ans += a);
a <<= 1;
b >>= 1;
(b & 1) && (ans += a);
a <<= 1;
b >>= 1;
(b & 1) && (ans += a);
a <<= 1;
b >>= 1;
(b & 1) && (ans += a);
a <<= 1;
b >>= 1;
(b & 1) && (ans += a);
a <<= 1;
b >>= 1;
return ans >> 1;
}
};
题目
写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
示例:
输入: a = 1, b = 1
输出: 2
提示:a, b 均可能是负数或 0 结果不会溢出 32 位整数
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/bu-yong-jia-jian-cheng-chu-zuo-jia-fa-lcof
分析
基本上就是二进制加法的思路,首先将产生的进位保存到carry,然后求进位加法(异或)的值,在代码中将这个值重新赋给了a。那么现在的问题就变成了a和进位的加法,要注意的是,此时的carry要左移一位。
代码
class Solution {
public:
int add(int a, int b) {
while(b){
int carry = a & b;
a = a ^ b;
b = (unsigned)carry << 1;
}
return a;
}
};