互联网公司面试题解析

原码、反码、补码

int a = -2147483648;
int b = 0x80000000;

System.out.println(a == b);
System.out.println(String.format("%d,%d,%d,%d,%d", ~a, -a, 1 - a, -1 - a, Math.abs(a)));
true
2147483647,-2147483648,-2147483647,2147483647,-2147483648

int用4个字节表示,每个字节8位,1位有两种状态,一共可以表示 pow(2,4 * 8)个数。因为有正数和负数的区别,最高位要保留,所以一共可以表示 2^31个负数,2^31个正数(这里所说的正数是值最高位符号位是0,从而0是正数),这样正整数的最大值是2^31-1.-2147483648是最小的负数。整数在计算机中都是以补码表示,大于等于0的补码是其原码,0的补码是0,负数的补码是反码加1

正1的原码(补码):0000,0000,0000,0000,0000,0000,0000,0001
-1的原码:1000,0000,0000,0000,0000,0000,0000,0001
-1反码:1111,1111,1111,1111,1111,1111,1111,1110
-1补码:1111,1111,1111,1111,1111,1111,1111,1111

反码不针对符号位,切记!

整数最大值的原码(补码):0111,1111,1111,1111,1111,1111,1111,1111
整数最小值的原码:1000,0000,0000,0000,0000,0000,0000,0000
整数最小值的反码:1111,1111,1111,1111,1111,1111,1111,1111
整数最小值的补码:1000,0000,0000,0000,0000,0000,0000,0000

整数最小值的原码等于其补码。整数的表示空间中,负数比正数多一个,因此,对整数的最小值求绝对值,32位整数装不下,从而溢出,绝对值依旧是个负数

正负转换是反码加1

负数最小值~:0111,1111,1111,1111,1111,1111,1111,1111,得到整数最大值
负数最小值求负-:1111,1111,1111,1111,1111,1111,1111,1111 + 1,从而1000,0000,0000,0000,0000,0000,0000,0000,这个仍然表示负数最小值

栈的使用

// 后缀表达式的优点
// 最左边一定是数字
// 不用括号,依靠运算符顺序确定运算符的优先级
// 更符合计算机的计算方式:从左到右读取后缀表达式,就可以将遇到的运算对象压入栈中,在遇到运算符的时候就弹出2个运算对象,完成计算后将结果压入栈中。最后留在栈中的就是计算结果

function solve(str) {
  const tokens = str.split(/\s*/).map(x => x.trim()).filter(x => x.length > 0);
  const isOperator = token => ['+', '-', '*', '/'].indexOf(token) !== -1;

  const opStack = [];
  const valueStack = [];

  // 忽略左括号
  // 遇到操作数放入值栈
  // 遇到操作符放入符号栈
  // 遇到右括号计算后缀表达式,放入值栈
  // 返回栈顶
  for (let token of tokens) {
    if (isOperator(token)) {
      opStack.push(token);
    } else if (token === '(') {
      continue;
    } else if (token === ')') {
      let num2 = valueStack.pop();
      let num1 = valueStack.pop();
      let op = opStack.pop();
      valueStack.push(`${num1}${num2}${op}`);
    } else {
      valueStack.push(token);
    }
  }
  return valueStack.pop();
}

// 解法1没有区分操作符的优先级,需要人肉加括号,例如:a+b*c-(d+e)/f要写成((a+(b*c))-((d+e)/f))才能识别
function solve2(str) {

  const priorityMap = {
    '+': 0,
    '-': 0,
    '*': 1,
    '/': 1,

    '(': 1000,
    ')': 1000
  };

  const isOpNum = token => priorityMap[token] === void 0;

  const opStack = [];
  const resultStack = [];

  const tokens = str.split(/\s*/).map(x => x.trim()).filter(x => x.length > 0);

  // 操作数入值栈
  // 左括号入符号栈
  // 遇到右括号则从符号栈中不断出栈,直至左括号出栈,并把出栈的内容放入值栈
  // 如果当前操作符的优先级大于栈顶优先级,入符号栈
  // 当前操作符优先级小于等于栈顶优先级,则一直出栈,并把出栈内容压入值栈

  // 右括号不入栈,碰到右括号需要从符号栈中向前扫描找到左括号,并以此将扫描的内容加入值栈
  for (let token of tokens) {
    if (isOpNum(token)) {
      resultStack.push(token);
    } else {
      if (opStack.length === 0) {
        opStack.push(token);
      } else {
        let topOp = opStack[opStack.length - 1];
        let topOpPriority = priorityMap[topOp];
        let curOpPriority = priorityMap[token];
        if (topOp === '(') {
          opStack.push(token);
        } else if (')' === token) {
          while (true) {
            let op = opStack.pop();
            if (op === '(') {
              break;
            }
            resultStack.push(op);
          }
        } else {
          if (curOpPriority > topOpPriority) {
            opStack.push(token);
          } else {
            // 当前运算符优先级小于栈顶运算符优先级
            while (curOpPriority <= topOpPriority) {
              resultStack.push(opStack.pop());
              if (opStack.length === 0) {
                break;
              }
              let top = opStack[opStack.length - 1];
              if (top === '(') {
                break;
              }
              topOpPriority = priorityMap[top];
            }
            opStack.push(token);
          }
        }
      }
    }
  }

  while (opStack.length !== 0) {
    resultStack.push(opStack.pop());
  }

  return resultStack.join('');
}

const ret = solve('((a+(b*c))-((d+e)/f))');
console.log(ret);

const ret2 = solve2('a+b*c-(d+e)/f');
console.log(ret2);

假设一行优先顺序存储三维数组A5[7],其中元素A0[0]的地址为1100,每个元素占用2个存储单元,求A4[2].

4个满的2维矩阵(67) + 3个满的一维矩阵(1 7),加2个偏移

offset = 6 7 + 3 7 + 2 = 191
1100 + 191 * 2 = 1482

马路上有编号1,2,3…,10十个路灯,为节约用电又看清路面,可以把其中的三只灯关掉,但不能同时关掉相邻的三只或两只,在两端的灯也不能关掉的情况下,求满足条件的关灯方法共有多少种?

问题转化为在7个亮着的等所形成的6个空隙中寻找3个位置房熄灭的等,C63 = 20

房间里有 8 人,分别佩戴着从 1 号到 8 号的纪念章,任选 3 人记录其纪念章号码, 最大的号码为 6 的概率:

最大为6 那么余下二个只能从1-5中选择,
选择方法数目为C(5, 2)
从8个号码中选择3个号码次数C(8, 3)
因此两个相除,比例为 C(5, 2)/C(8, 3) = (54 / 2) / (87*6/ 6) = 5 / 28

58同城北京租房列表页共有3个广告位,广告库中共有5个经纪人,每个经纪人发布了2条广告房源参与此列表页3个广告位的随机展示(即每条广告房源获得展示的概率是一样的),则此列表页展示时,同时展示同一个经纪人的两条房源的概率是:

共5*2=10条广告,广告列有3空位,所以是总共情形:C10 3=120;
同一经纪人(C5 1)的两条房源(共3条,已有2条,则需要在剩下的8条中选1条,C10-2 1):C 5 1*C 10-2 1=40;
所以40/120=1/3

数组 A 由 1000W 个随机正整数(int)组成,设计算法,给定整数 n,在 A 中找出符合 如下等式:n=a+b 的 a 和 b,说明算法思路以及时间复杂度是多少

将数组排序,杂度 n*logn 在从头开始,假设第 i 个位置时 arr[i],那就在 i 到 1000 万之 间找 n - arr[i] 二分查找的效率是logn,由于当arr[i] > n/2 时就不用找了,所以最终效 率 2*n*logn.

斗地主是中国非常流行的一种牌类游戏:一副扑克 54 张牌,3 人轮抓,每人 17 张, 3 张底牌。请问,同一个人 17 张手牌就抓到火箭(即同时抓到大小王)的概率是多少?

一个人抓到第一张王的概率=17/51,抓到第二张王概率=16/50,所以单独一个人 抓到概率为:17/5116/50,那么 3 人中出现一个人的概率是 317/5116/50 所以最后结果为:C(52,3)/C(54,3)317/5116/50=0.285

计算机网络

属于网络112.10.200.0/21的地址是()
A 112.10.206.0
B 112.10.217.0
C 112.10.224.0
D 112.10.198.0

ip地主是32位表示,点分十进制中的2个十进制已经去了16位,因此,第三个十进制转化成二进制后保留21-16=5位,后面的数可以全0可以全1。200转化成二进制是11001000,保留前5位,即11001,则第三位最小值11001000,最大值11001111,即200~207.可排除BCD。

java基础

Object o = new Object(){
    @Override
    public boolean equals(Object obj) {
        return true;
    }
};

System.out.println(o.equals(false)); // true
byte b1 = 1, b2 = 2, b3, b6;

final byte b4 = 4,
        b5 = 6;

b6 = b4 + b5; 
b3 = b1 + b2; // 编译不通过

被final修饰的变量是常量,这里的b6=b4+b5可以看成是b6=10;在编译时就已经变为b6=10了而b1和b2是byte类型,java中进行计算时候将他们提升为int类型,再进行计算,b1+b2计算后已经是int类型,赋值给b3,b3是byte类型,类型不匹配,编译不会通过,需要进行强制转换。Java中的byte,short,char进行计算时都会提升为int类型。

计算斐波那契数列第n项的函数定义如下

int fib(int n){ 
     if(n==0) 
        return 1; 
     else if(n==1) 
        return 2; 
     else 
        return fib(n-1)+fib(n-2);
}

若执行函数调用表达式fib(10),函数fib被调用的次数是:

设f(n) 表示执行fib(n)函数的次数,那么显然地推公式: f(n) = f(n-1) + f(n-2) + 1 (1表示执行到了fib(n)的时候执行了一次fib函数)

f(10) = f(9) + f(8) + 1

f(0) = 1
f(1) = 1
f(2) = 3
f(3) = 5
f(4) = 9
f(5) = 15
f(6) = 25
f(7) = 41
f(8) = 67
f(9) = 109
f(10) = 177

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值