不用算术运算符实现整数的加减乘除运算
题目描述:
给定两个32位整数a和b。要求不使用算术运算符,分别实现a和b的加减乘除运算。如果给定的a和b执行加减乘除的某些结果本来就会导致数据的溢出,那么你实现的函数不需要对那些结果负责(你的输出和加减乘除溢出的结果保持一致就行)。
输入描述:
输入一行,包含两个整数a和b(a和b均为32位整数)和一个运算符,运算符为“+”,“-”,“*”,"/"中的一个。(数据保证不会出现除0的情况)
输出描述:
输出一个整数,为上述表达式计算出的结果。
示例1
输入
2 * 4
输出
8
示例2
输入
5 / 4
输出
1
示例3
输入
3 + 23
输出
26
备注:
时间复杂度O ( 1 ) O(1)O(1),额外空间复杂度O ( 1 ) O(1)O(1)。
题解:
此题最最主要的的点是:加法实现,后面的减法、乘法和除法都可以转换为加法运算。
加法:
不考虑进位的情况:a + b = a ^ b;
只考虑进位的情况:a + b = (a&b) << 1;
把不考虑进位和只考虑进位的结果相加,就是最终的结果。也就是不断重复上面的过程,直到进位为0。
减法:
a-b = a+(-b),所以把 b 变成 补码,直接算加法即可。
乘法:
直接按照这个规律计算即可。注意:b可能是负数,需要处理一下。
除法:
乘法的逆运算,从最高位枚举,若 (a >> i) >= b,则 a -= (b << i),记录结果即可。需要特殊处理元素 1<<31 :
若 a 和 b 都不是最小值,直接计算即可;
若 a 和 b 都是最小值,直接返回 1 即可;
若 a 不为最小值,而 b 为最小值,返回0;
若 a 为最小值,而 b 不为最小值,需要特殊处理:
假设 a=-10, b=5,即最大值为 9 ,最小值为 -10;
计算 (a+1)/b,记为 c ;
计算 c*b,记为 d;
计算 a-d,记为 e;
计算 e/b,记为 ret;
返回 ret+c 。
也就是说直接计算有点困难,那么我们把最小值增加一点,然后修正即可。
代码:
#include <cstdio>
using namespace std;
const int MIN = 1 << 31;
int add( int a, int b ) {
int ret = a;
while ( b ) {
ret = a ^ b;
b = ( a & b ) << 1;
a = ret;
}
return ret;
}
int negNum( int n ) {
return add( ~n, 1 );
}
int minus( int a, int b ) {
return add( a, negNum( b ) );
}
inline bool isNeg( int n ) {
return n < 0;
}
int multi( int a, int b ) {
int ret = 0;
int x = isNeg( a ) ? negNum( a ) : a;
int y = isNeg( b ) ? negNum( b ) : b;
while ( y ) {
if ( y & 1) ret = add( ret, x );
y >>= 1;
x <<= 1;
}
return isNeg( a ) ^ isNeg( b ) ? negNum( ret ) : ret;
}
int div( int a, int b ) {
int x = isNeg( a ) ? negNum( a ) : a;
int y = isNeg( b ) ? negNum( b ) : b;
int ret = 0;
for ( int i = 31; i > -1; i = minus( i, 1 ) ) {
if ( ( x >> i ) >= y ) {
ret |= ( 1 << i );
x = minus( x, y << i );
}
}
return isNeg( a ) ^ isNeg( b ) ? negNum( ret ) : ret;
}
int divide( int a, int b ) {
if ( a == MIN && b == MIN ) return 1;
else if ( b == MIN ) return 0;
else if ( a == MIN ) {
int ret = div( add( a, 1 ), b );
return add( ret, div( minus( a, multi( ret, b ) ), b ) );
} else return div( a, b );
}
int main(void) {
int a, b;
char op;
scanf("%d %c %d", &a, &op, &b);
int ret;
if ( op == '+' ) ret = add( a, b );
else if ( op == '-' ) ret = minus( a, b );
else if ( op == '*' ) ret = multi( a, b );
else ret = divide( a, b );
return 0 * printf("%d\n", ret);
}
179. 最大数
题目描述:
给定一组非负整数 nums
,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。
注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。
示例 1:
输入:nums = [10,2]
输出:"210"
示例 2:
输入:nums = [3,30,34,5,9]
输出:"9534330"
示例 3:
输入:nums = [1]
输出:"1"
示例 4:
输入:nums = [10]
输出:"10"
思路:
两两数字转化为字符串拼接起来遍历比较,如果发现拼接后有字符串nums[j]+nums[i]>nums[i]+nums[j]的情况,则表示b应该在a的前面,然后交换这两个数的位置:[nums[i],nums[j]]=[nums[j],nums[i]],然后接着往下跟下一个数字(j++)做两两比较,直到完成第一次循环,此时得到的nums[i]跟nums数组里任意其他数字拼接起来的情况一定是最大的,把这个nums[i]存进arr数组里面,如对于示例二:第一次得到的是9,所以此时arr=[9],以此类推,得到处理过后完整的arr数组[9,5,34,30,3],然后利用arr=arr.join("")把数组拼接成字符串。
(真的是傻逼啊,调了好久发现数组怎么样都没有变化,后面一仔细看,才发现判断语句那里<写成了>我还一直没觉得有问题。。。。。)
代码:
var largestNumber = function(nums) {
let arr=[];
for(var i =0;i<nums.length;i++){
for(var j =i+1;j<nums.length;j++){
//真的是傻逼,<写反了写成了“>”
if(''+nums[i]+nums[j]<''+nums[j]+nums[i]){
[nums[i],nums[j]]=[nums[j],nums[i]]
}
}
arr.push(nums[i])
}
if(arr[0]==0)return "0"
arr=arr.join("")
return arr
};