澳门新萄京官方网站-www.8455.com-澳门新萄京赌场网址

蓝杯三十陆,外人家的面试题

2019-04-26 作者:澳门新萄京赌场网址   |   浏览(113)

外人家的面试题:贰个平头是或不是是“四”的N次幂

2016/05/30 · 基本功才具 · 2 评论 · 算法

正文作者: 伯乐在线 - 10年踪迹 。未经小编许可,禁止转发!
接待插手伯乐在线 专栏我。

这是 leetcode.com 的第贰篇。与上一篇同样,大家争论共同相对简便易行的题目,因为学习总重申遵纪守法。而且,固然是轻便的主题素材,追求算法的无比的话,在那之中也是有高校问的。

外人家的面试题:总结“壹”的个数

2016/05/27 · JavaScript · 5 评论 · Javascript, 算法

正文小编: 伯乐在线 - 拾年踪迹 。未经小编许可,禁止转发!
迎接到场伯乐在线 专栏撰稿人。

小胡子哥 @Barret李靖 给本身引入了一个写算法刷题的地点 leetcode.com,没有 ACM 那么难,但难题很风趣。而且听别人讲这一个难题都来源于一些铺面包车型客车面试题。可以吗,解解外人集团的面试题其实很有趣,既能整理思路磨炼才能,又不用操心漏题 ╮(╯▽╰)╭。

长途电话短说,让大家来看一道题:

算法磨练 数位分别 

Problem Description

1、Merge Two Binary Trees

Given two binary trees and imagine that when you put one of them to cover the other, some nodes of the two trees are overlapped while the others are not.
You need to merge them into a new binary tree. The merge rule is that if two nodes overlap, then sum node values up as the new value of the merged node. Otherwise, the NOT null node will be used as the node of new tree.

Example 1:
Input: 
    Tree 1                     Tree 2                  
          1                         2                             
         /                        /                             
        3   2                     1   3                        
       /                                                    
      5                             4   7                  
Output: 
Merged tree:
         3
        / 
       4   5
      /     
     5   4   7

Note: The merging process must start from the root nodes of both trees.

题意:将七个2叉树合并成一个,要求就算1致节点上都有值,则将其相加,假如唯有一个节点有值,则以改值填充,假使都没值,该节点为空。

思路:以一个树为主树,另2个树为从树,同时遍历五个树,假诺五个节点都有值,则将从树的值加到主树上,如若从树有值,主树为空,则利用从树的值,填充该节点,假设从树为空,则毫不管。

代码完结,使用递归:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
        if(t1 != null && t2 != null) {
            t1.left = mergeTrees(t1.left,t2.left);
            t1.right = mergeTrees(t1.right,t2.right);
            t1.val  = t2.val;
            return t1;
        }
        return t1 == null ? t2 : t1;
    }
}

“4”的平头次幂

给定三个叁拾贰位有标识整数(32 bit signed integer),写一个函数,检查这几个平头是还是不是是“四”的N次幂,那里的N是非负整数。

例如:

  • 给定 num = 16,返回 true,因为 16 = 42
  • 给定 num = 5,返回 flase

叠加条件: 你可见不用循环和递归吗?

统计“1”的个数

给定一个非负整数 num,对于自便 i,0 ≤ i ≤ num,总计 i 的值对应的贰进制数中 “一” 的个数,将这一个结果回到为3个数组。

例如:

当 num = 5 时,再次来到值为 [0,1,1,2,1,2]。

/** * @param {number} num * @return {number[]} */ var countBits = function(num) { //在此处落成代码 };

1
2
3
4
5
6
7
/**
* @param {number} num
* @return {number[]}
*/
var countBits = function(num) {
    //在此处实现代码
};

时刻限定:1.0s  内存限制:512.0MB

求A^B的最后二位数表示的整数。
证实:A^B的意思是“A的B次方”

2、leetcode Counting Bits

leetcode Counting Bits
Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1’s in their binary representation and return them as an array.
Example:
For num = 5 you should return [0,1,1,2,1,2].
Follow up:
It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass?
Space complexity should be O(n).
Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c or in any other language.

题意:给定多少个平头num,输出0~num中每一种数的2进制一的个数

解题思路

比如忽视“附加条件”,那题还挺轻易的对啊?差不多是随手拈来:

版本1

JavaScript

function isPowerOfFour(num){ while(!(num % 4)){ num /= 4; } return num === 1; }

1
2
3
4
5
6
function isPowerOfFour(num){
    while(!(num % 4)){
        num /= 4;
    }
    return num === 1;
}

本子1 接近异常粗略、很有力的样板,它的时刻复杂度是 log4N。有同学说,还是能做一些壹线的改造:

版本1.1

JavaScript

function isPowerOfFour(num){ while(!(num % 4)){ num >>>= 2; } return num === 1; }

1
2
3
4
5
6
function isPowerOfFour(num){
    while(!(num % 4)){
      num >>>= 2;
    }
    return num === 1;
}

上边包车型大巴代码用位移代替除法,在任何语言中更加快,鉴于 JS 常常景况下卓殊坑的位运算操作,不自然速度能变快。

好了,最重视的是,不管是 版本一 依旧 版本1.一就像都不知足大家面前提到的“附加条件”,即不选取循环和递归,或然说,大家必要寻觅O(1) 的解法。

遵从规矩,大家先探讨十分钟,然后往下看 ——


解题思路

那道题咋一看还挺简单的,无非是:

  • 兑现三个措施 countBit,对自便非负整数 n,总计它的二进制数中“一”的个数
  • 循环 i 从 0 到 num,求 countBit(i),将值放在数组中回到。

JavaScript中,计算 countBit 能够取巧:

function countBit(n){ return n.toString(2).replace(/0/g,"").length; }

1
2
3
function countBit(n){
    return n.toString(2).replace(/0/g,"").length;
}

上面包车型地铁代码里,大家直接对 n 用 toString(2) 转成二进制表示的字符串,然后去掉个中的0,剩下的便是“1”的个数。

接下来,大家写一下总体的程序:

版本1

function countBit(n){ return n.toString(2).replace(/0/g,'').length; } function countBits(nums){ var ret = []; for(var i = 0; i <= nums; i ){ ret.push(countBit(i)); } return ret; }

1
2
3
4
5
6
7
8
9
10
11
function countBit(n){
   return n.toString(2).replace(/0/g,'').length;
}
 
function countBits(nums){
   var ret = [];
   for(var i = 0; i <= nums; i ){
       ret.push(countBit(i));
   }
   return ret;
}

位置那种写法10分收益,好处是 countBit 利用 JavaScript 语言特征达成得非凡简短,坏处是只要明日要将它改写成其它语言的版本,就有一点都不小或然懵B了,它不是很通用,而且它的性质还在于 Number.prototype.toString(贰) 和 String.prototype.replace 的兑现。

之所认为了追求更加好的写法,大家有须要怀想一下 countBit 的通用落成法。

咱俩说,求1个平头的2进制表示中 “壹” 的个数,最平日的当然是2个 O(logN) 的艺术:

function countBit(n){ var ret = 0; while(n > 0){ ret = n & 1; n >>= 1; } return ret; }

1
2
3
4
5
6
7
8
function countBit(n){
    var ret = 0;
    while(n > 0){
        ret = n & 1;
        n >>= 1;
    }
    return ret;
}

由此大家有了版本2

诸如此类实现也很简短不是吧?可是如此完结是还是不是最优?建议此处思虑10分钟再往下看。


交给此题   

 Input

法1:仔细分析一下可窥见当一个数是二的平头幂的时候,2进制一的个数为一。之后就是前二个行列 一,如:

1、2(0010) = 1
2、3(0011) = 2(0010) 1(0001) = 2
3、6(0110) = 4(0100) 2(0010) = 1 1 = 2
4、7(0111) = 4(0100) 3(0011) = 1 2 = 3
5、9 (1001) = 8(1000) 1(0001) = 1 1 = 2
固然把贰个数分解为小于它的最大2的平头幂 x
代码落成:

public static int[] countBits(int num) {
        int[] res = new int[num   1];
        int pow2 = 1,before = 1;
        for(int i = 1;i<=num;i  ){
            if(pow2 == i) {
                res[i] = before = 1;
                pow2 <<= 1;
            } else {
                res[i] = res[before]   1;
                before  ;
            }
        }
        return res;
    }

决不循环和递归

骨子里那道题真心有诸两种思路,计算指数之类的对数学系学霸们一同不是题材嘛:

版本2

JavaScript

const log4 = Math.log(4); function isPowerOfFour(num){ var n = Math.log(num) / log4; return n === (0|n); }

1
2
3
4
5
const log4 = Math.log(4);
function isPowerOfFour(num){
    var n = Math.log(num) / log4;
    return n === (0|n);
}

啊,通过对数公式 logm(n) = log(n) / log(m) 求出指数,然后推断指数是否3个平头,那样就足以毫无循环和递归解决难点。而且,还要注意细节,能够将 log肆 当做常量抽出出来,那样并非每回都再一次计算,果然是学霸范儿。

不过呢,利用 Math.log 方法也算是某种意义上的违犯禁令吧,有未有永不数学函数,用原生方法来化解吗?

自然有了!而且还不止一种,大家能够持续想30秒,要起码想出一种啊 ——


更快的 countBit

上贰个版本的 countBit 的时刻复杂度已经是 O(logN) 了,难道还能越来越快吗?当然是足以的,我们不须要去看清每1个人是或不是“①”,也能领悟n 的二进制中有多少个“一”。

有一个门槛,是基于以下三个定律:

  • 对于随便 n, n ≥ 1,有如下等式创制:

countBit(n & (n - 1)) === countBit(n) - 1

1
countBit(n & (n - 1)) === countBit(n) - 1

这么些很轻便了然,我们只要想转手,对于随便 n,n – 一 的2进制数表示正好是 n 的二进制数的最末一个“壹”退位,由此 n & n – 壹 正要将 n 的最末壹个人“1”消去,比如:

  • 6 的二进制数是 1拾, 蓝杯三十陆,外人家的面试题。5 = 6 – 1 的2进制数是 10壹,6 & 5 的二进制数是 110 & 101 == 100
  • 88 的二进制数是 101一千,87 = 88 – 1 的二进制数是 10十11一,88 & 87 的二进制数是 1011000 & 1010111 == 1010000

于是乎,大家有了2个更加快的算法:

版本3

function countBit(n){ var ret = 0; while(n > 0){ ret ; n &= n - 1; } return ret; } function countBits(nums){ var ret = []; for(var i = 0; i <= nums; i ){ ret.push(countBit(i)); } return ret; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function countBit(n){
    var ret = 0;
    while(n > 0){
        ret ;
        n &= n - 1;
    }
    return ret;
}
 
function countBits(nums){
   var ret = [];
   for(var i = 0; i <= nums; i ){
       ret.push(countBit(i));
   }
   return ret;
}

上面的 countBit(88) 只循环 3 次,而“版本2”的 countBit(88) 却供给循环 7 次。

优化到了这么些程度,是否百分百都终止了吧?从算法上的话就像是已经是极致了?真的吗?再给我们30 秒时间思量一下,然后再往下看。


难点讲述

输入数据蕴涵七个测试实例,每一个实例占一行,由多少个正整数A和B组成(一<=A,B<=一千0),假若A=0, B=0,则意味输入数据的终结,不做拍卖。

法2:一个数*二正是把它的2进制全体左移壹个人,也正是说壹的个数是相当的,那小编我们尽管将四个数右移感觉呢?如若那几个数是偶数,右移1个人刚刚是num/二,要是是奇数,则是num/二 1。大家能够取得以下公式:

res[i] = res[i >> 1] (i & 一);(要是是奇数,i & 一获得一,要是是偶数i & 1获得0)

大家的代码能够这么改写:

public static int[] countBits2(int num) {
        int[] res = new int[num   1];
        for (int i = 1; i <= num; i  ) {
            res[i] = res[i >> 1]   (i & 1);
        }
        return  res;
    }

绝不内置函数

其一主题材料的显要思路和上一道题类似,先思量“四”的幂的2进制表示:

  • 40 = 1B
  • 41 = 100B
  • 42 = 10000B
  • 43 = 1000000B
  • ……

也正是各样数比上叁个数的2进制前面多多个零嘛。最根本的是,“四”的幂的二进制数唯有一 个“1”。要是条分缕析阅读过上1篇,你就会领会,决断三个2进制数惟有 三个“一”,只供给:

JavaScript

(num & num - 1) === 0

1
(num & num - 1) === 0

然则,二进制数唯有 3个“一”只是“四”的幂的须要非丰富原则,因为“二”的奇多次幂也唯有 一个“1”。所以,大家还需求增大的判断:

JavaScript

(num & num - 1) === 0 && (num & 0xAAAAAAAA) === 0

1
(num & num - 1) === 0 && (num & 0xAAAAAAAA) === 0

怎么是 num & 0xAAAAAAAA === 0? 因为这几个有限帮助 num 的2进制的不行 “一” 出现在“奇数位”上,也就保险了那一个数确实是“4”的幂,而不只只是“贰”的幂。

末段,我们获得完全的本子:

版本3

JavaScript

function isPowerOfFour(num) { return num > 0 && (num & (num-1)) === 0 && (num & 0xAAAAAAAA) === 0; };

1
2
3
4
function isPowerOfFour(num) {
    return num > 0 && (num & (num-1)) === 0
                   && (num & 0xAAAAAAAA) === 0;
};

上边的代码要求丰裕 num > 0,是因为 0 要解除在外,不然 (0 & -一) === 0 也是 true


countBits 的岁月复杂度

考虑 countBits, 上边的算法:

  • “版本一” 的年华复杂度是 O(N*M),M 取决于 Number.prototype.toString 和 String.prototype.replace 的复杂度。
  • “版本二” 的年华复杂度是 O(N*logN)
  • “版本叁” 的时刻复杂度是 O(N*M),M 是 N 的2进制数中的“壹”的个数,介于 壹 ~ logN 之间。

上边四个版本的 countBits 的日子复杂度都不止 O(N)。那么有未有时间复杂度 O(N) 的算法呢?

实际,“版本叁”已经为大家提示了答案,答案就在上边的不行定律里,笔者把越发等式再写二回:

countBit(n & (n - 1)) === countBit(n) - 1

1
countBit(n & (n - 1)) === countBit(n) - 1

也正是说,若是大家驾驭了 countBit(n & (n - 1)),那么我们也就驾驭了 countBit(n)

而小编辈知晓 countBit(0) 的值是 0,于是,大家能够不会细小略的递推:

版本4

function countBits(nums){ var ret = [0]; for(var i = 1; i <= nums; i ){ ret.push(ret[i & i - 1] 1); } return ret; }

1
2
3
4
5
6
7
function countBits(nums){
   var ret = [0];
   for(var i = 1; i <= nums; i ){
       ret.push(ret[i & i - 1] 1);
   }
   return ret;
}

原本就像此简单,你想到了啊 ╮(╯▽╰)╭

上述正是持有的内容,轻松的主题素材思索起来很有趣吗?攻城狮就应有追求八面见光的算法,不是啊?

那是 leetcode 算法面试题连串的首先期,下一期大家钻探除此以外1道题,那道题也很风趣:看清一个非负整数是或不是是 四 的整数次方,别告诉小编你用循环,想想更抢眼的办法吗~

打赏帮衬本人写出越多好作品,多谢!

打赏笔者

  编写三个程序,输入二个一千以内的正整数,然后把那几个平头的每一位数字都分离出来,并逐条地呈现。

 Output

其他版本

地点的版本已经符合了我们的要求,时间复杂度是 O(1),不用循环和递归。

除此以外,我们还足以有其它的本子,它们严厉来说有的如故“犯规”,然而大家依然得以学学一下那个思路:

版本4:用 Math.sqrt

JavaScript

function isPowerOfFour(num) { num = Math.sqrt(num); return num > 0 && num === (0|num) && (num & (num-1)) === 0; };

1
2
3
4
function isPowerOfFour(num) {
    num = Math.sqrt(num);
    return num > 0 && num === (0|num) && (num & (num-1)) === 0;
};

本子5:用正则表明式

JavaScript

function isPowerOfFour(num) { return /^1(00)*$/g.test(num.toString(2)); };

1
2
3
function isPowerOfFour(num) {
    return /^1(00)*$/g.test(num.toString(2));
};

如上正是负有的始末,那道题有那多少个五种思路,格外风趣,也正如考验基本功。假使你有友好的思绪,能够留言插足座谈。

下壹期大家顶牛其余一道题,那道题比这两道题要难有的,但也更有意思:给定二个正整数 n,将它拆成至少多少个正整数之和,对拆出的正整数求乘积,再次回到能够得到的乘积最大的结果

想壹想你的解法是如何?你能够尽可能缩小算法的时间复杂度吗?期待您的答案~~

打赏协助自身写出愈来愈多好小说,感谢!

打赏小编

打赏匡助自个儿写出更多好文章,多谢!

任选1种支付格局

图片 1 图片 2

3 赞 8 收藏 5 评论

  输入格式:输入只有1行,即一个一千以内的正整数。

对此每一种测试实例,请输出A^B的末尾三个人代表的平头,每一个输出占1行。

打赏补助自个儿写出更加多好小说,多谢!

任选一种支付办法

图片 3 图片 4

1 赞 7 收藏 2 评论

关于作者:十年踪迹

图片 5

月影,奇舞蹈艺术团准将,热爱前端开拓,JavaScript 程序员一枚,能写代码也能打杂卖萌说段子。 个人主页 · 笔者的稿子 · 14 ·     

图片 6

  输出格式:输出唯有1行,即该整数的每1位数字,之间用空格隔断。

  简来讲之那题就是须要高次幂,有三种艺术能够兑现。

至于小编:十年踪迹

图片 7

月影,奇舞蹈艺术团中校,热爱前端开辟,JavaScript 工程师壹枚,能写代码也能打杂卖萌说段子。 个人主页 · 笔者的篇章 · 14 ·     

图片 8

  输入输出样例

  第二总相比较土鳖,每回乘完对1000取余也足以过。

样例输入

  作者要讲的是第二种听起来很伟大上的措施——快速幂。为啥叫快快幂呢?因为用它求幂不慢,对于x^n,复杂度为O(logn),是还是不是很吊!急速幂的规律是把幂分解,把2个比相当大的幂分解成异常的小的几部分。比方:

769

1一的二进制是十1一

样例输出

11 = 2³×1 2²×0 2¹×1 2º×1

7 6 9

因此,我们将a¹¹转化为 图片 9

#include <stdio.h>

即把n化为二进制数,每种为一的位都以十分小的一片段。那样能够用八个循环来消除。下边是高速幂的非递归代码,权且忽略max

void getResult(int num)

int cal(int x, int n, int max){

{

  int sum = 一;    //最终输出的结果
  while (n > 0){   //当幂降为0是终结
  if (n & 一)      //位运算,&是按位与,当两边都为一,表明式为一,那个是用来剖断2进制数最终一人是不是为1,那里n是以贰进制的款型相比较的

    //出口

    sum = sum*x%max;//如若为1,sum将要乘x^i,i为该位在2进制数中的地方
  n >>= 1;      //>>为位运算符,右移一个人,即去掉已经计算过的部分
  x = x*x%max;    //用来标志记录x^二^i,循环i次即去掉了i位,当第i 一位为一时,sum将在乘x^二^i;
  }
  return sum;//循环截止再次来到结果。
}

    if(num<10)

  未来来讲max的法力,用来把数变小的,我们得以想象假使是比十分的大的数的非常高次方,乘一回后数据比较大不恐怕用别样贰个为主数据类型表示,而且那也是不须求的,经常大家只需求明白最终若干位的值,那就足以用到取余了,余数的幂和原数的幂在余数的位数上是千篇壹律的,所以每一遍进行乘法运算后都要取余,当然倘诺数额相当的小也足以不用取余。

    {

  好了,感到自己早就讲的很详细了!!真的是全力以赴了。。。

        printf("%d ",num);

下边贴上地方那题的代码

        return ;

 1 #include<iostream>
 2 using namespace std;
 3 
 4 int cal(int x, int n, int max){
 5     int sum = 1;
 6     while (n > 0){
 7         if (n & 1)
 8             sum = sum*x%max;
 9         n >>= 1;
10         x = x*x%max;
11     }
12     return sum;
13 }
14 int main(){
15     int x, n;
16     while ((cin >> x >> n) && (x || n)){
17         cout << cal(x, n, 1000) << endl;
18     }
19     return 0;
20 }

    }

 

    //递归

      getResult(num/10);

 

  printf("%d ",num);

}

int main()

{

  int n; 

  scanf("%d",&n);

  getResult(n);

  printf("n");

  return 0;

}

思路分析:

1定义变量:一个低于一千的整数;

二输入整数;

叁调用函数将各样数字分别:要是该数小于十,则输出;假使该数大于十,则用递归将其分别并出口。

算法练习 陆-贰递归求2进制表示位数 

时限:10.0s  内部存款和储蓄器限制:256.0MB

交给此题   

题目讲述

  给定二个10进制整数,重回其对应的2进制数的位数。举例,输入10进制数九,其对应的贰进制数是拾0壹,因而位数是四。

样例输入

叁个满意标题须要的输入表率。

9

样例输出

9

4

与地方的样例输入相应的出口。

数据规模和预定

  输入数据中每一个数的范围。

  例:输入在int表示范围内。

#include"stdio.h"

int main()

{

  long int n;

    int s=0;

    scanf("%d",&n);

    while(n!=0)

{

      s ;

      n=n/2;

}

printf("%dn",s);

return 0;

思路分析:

1定义变量:一个10进制整数,位数(起头化为0);

2输入10进制整数;

叁循环直至该数为0跳出,位数加一,转变为二进制是该数被二整除;

四出口位数。

算法演习 友好数 

光阴限制:一.0s  内部存款和储蓄器限制:25六.0MB

提交此题   

题目讲述

  有多个整数,借使每一种整数的约数和(除了它本人以外)等于对方,大家就称那对数是友善的。比如:

  九的约数和有:一 叁=四

  4的约数和有:一 二=三

  所以9和四不是和睦的。

  220的约数和有:一 二 四 5 拾 11 20 22 44 5伍 1十=284

  28肆的约数和有:一 二 4 7一 14二=220

  所以220和2捌肆是友善的。

  编写程序,判定五个数是或不是是友好数。

输入格式

  1行,多个整数,由空格分隔

出口格式

  假如是投机数,输出"yes",不然输出"no",注意不带有引号。

样例输入

220 284

样例输出

yes

多少规模和平条目定

  七个整数都自愧不及10000

#include "stdio.h"

int fun(int n){

    int count=0,i;

    for(i=1;i < n;i ){

        if(n % i==0){

            count =i;

        }

    }

    return count;

}

int main(){

    int num1,num2;

    int a,b;

    scanf("%d%d",&num1,&num2);

    b=fun(num1);

    a=fun(num2);

    if(a==num1 && b==num2){

        printf("yesn");

    }

    else{

        printf("non");

    }

    return 0;

}

思路分析:

壹定义变量:五个整数;

二输入多少个整数;

3调用函数:

(一) 定义变量:约数,约数和(伊始化为0);

(二)for语句循环(从壹伊始,循环到该数),用if语句判定该数是否被约数整除余数为0,假使为0,则增加;

(3)重返值为约数和;

四if语句剖断是还是不是为温馨数,假若是则输出yes,不不过为no。

本文由澳门新萄京官方网站发布于澳门新萄京赌场网址,转载请注明出处:蓝杯三十陆,外人家的面试题

关键词: