剑指offer之其它

目录

面试题15:二进制中1的个数

面试题16:数值的整数次方

面试题49:丑数

面试题57:和为s的数字

拓展:和为S的连续正数序列

面试题62:圆圈中最后剩下的数字

面试题64:求1+2+3+...+n

面试题65:不用加减乘除做加法


面试题15:二进制中1的个数

题目:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

分析:把一个整数减去1,再和原整数做与运算,会把该整数最右边的1变成0。

   public int NumberOf1(int n) {
        int count = 0;
        while(n != 0){
            count++;
            n = (n-1) & n;
        }
        return count;
    }

面试题16:数值的整数次方

题目:给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。保证base和exponent不同时为0

分析:当指数为负数时,应先对指数求绝对值,算出次方再求倒数。但不能对0求倒数,所以对0应该格外处理。另外用右移运算符代替除以2,以及用位于运算符代替求余运算符来提高效率。

    public double Power(double base, int exponent) {
        if(base == 0)
            return 0.0;
        if(exponent < 0)
            return 1.0 / util(base,Math.abs(exponent));
        else
            return util(base,exponent);
    }

    private double util(double base, int abs) {
        if(abs == 0)
            return 1;
        if(base == 1)
            return base;
        double result = util(base,abs >> 1);
        result *= result;
        if((abs & 1)== 1)
            result *= base;
        return result;
  }

面试题49:丑数

题目:把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。习惯上我们把1当作第一个丑数。求按从小到大的顺序的第N个丑数。

分析:根据丑数的定义,丑数是另一个丑数乘以2、3或者5的结果(1除外),因此,可以创建一个数组,里面的数字时排好序的丑数,每个丑数都是前面的丑数乘以2、3或者5得到的。在生成下一个丑数时,该丑数肯定是前面某个丑数乘以2,3,5的结果。对乘以2而言,肯定存在某一个丑数T2,排在它之前的每一个丑数乘以2得到的结果都会小于已有的最大丑数,在它之后的每一个丑数乘以2得到的结果都会太大。我们只需记下这个丑数的位置,同时每次生成新的丑数的时候,去更新这个T2.对乘以3和5而言,也存在这同样的T3和T5.

    public int GetUglyNumber_Solution(int index) {
        if(index < 1)
            return 0;
        int[] ugly = new int[index];
        ugly[0] = 1;
        int x = 0,y = 0,z = 0;
        for(int i = 1;i < index;i++){
            int min = Min(ugly[x] * 2,ugly[y] * 3,ugly[z] * 5);
            ugly[i] = min;
            while(ugly[x] * 2 <= min)
                x++;
            while(ugly[y] * 3 <= min)
                y++;
            while(ugly[z] * 5 <= min)
                z++;
        }
        return ugly[index-1];
    }

面试题57:和为s的数字

题目:输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。

分析:由于数组是排序的,可以先在数组中选择两个数字,根据和与S的大小来判定选择小的数字还是大的数字。

    public ArrayList<Integer> FindNumbersWithSum(int [] array, int sum) {
        ArrayList<Integer> result = new ArrayList<>();
        if (array == null || array.length == 0)
            return result;
        int low = 0, high = array.length - 1;
        while (low < high) {
            if (array[low] + array[high] == sum) {
                result.add(array[low]);
                result.add(array[high]);
                return result;
            }
            else if (array[low] + array[high] > sum)
                high--;
            else
                low++;
        }
        return result;
    }

拓展:和为S的连续正数序列

题目:输入一个整数s,找出所有和为s的连续正数序列(至少含有两个数)。

分析:用两个数分别表示序列的最大值和最小值,首先初始化small为1,big为2,如果序列和大于s,则去掉较小的值,反之则增大big。因为序列至少要有两个数,一直增加small到(1+s)/ 2为止。

    public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<>();
        int mid = (1 + sum) >> 1;
        int small = 1,big = 2;
        int count = small + big;
        while(small < mid){
           while(count > sum && small < mid)
               count -= small++;
           if(count == sum){
                ArrayList<Integer> list = new ArrayList<>();
                for(int i = small;i <= big;i++){
                    list.add(i);
                }
                result.add(list);
           }
           count += ++big;
        }
        return result;
    }

面试题62:圆圈中最后剩下的数字

题目:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)。如果没有小朋友,请返回-1。

分析:方法一,用环形链表模拟圆圈的经典解法,可以创建一个共有n个节点的环形链表,然后每次在这个链表中删除第m个节点,这样的时间复杂度为O(mn),空间复杂度为O(n)。方法二,分析每次被删除的数字的规律并直接计算出圆圈中最后剩下的数字。

    //n个小孩,删除第m个
    public int LastRemaining_Solution(int n, int m) {
        if(n < 1 || m < 1)
            return -1;
        int res = 0;
        for(int i = 2;i <= n;i++)
            res = (res + m) % i;
        return res;
    }

面试题64:求1+2+3+...+n

题目:求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

分析:方法一,利用构造函数求解,创建n个自创类型的实例即可。方法二,递归求解,缺陷是n不能很大。

面试题65:不用加减乘除做加法

题目:写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

分析:可以用位运算来代替。第一步不考虑进位对每一位相加,可以用异或来代替;第二步考虑进位,就是与运算后左移以为即可。

    public int Add(int num1,int num2) {
        int sum ,carry;
        while(num2 != 0){
            sum = num1 ^ num2;
            carry = (num1 & num2) << 1;
            num1 = sum;
            num2 = carry;
        }
        return num1;
    }

猜你喜欢

转载自blog.csdn.net/Nibaby9/article/details/104126811