劍指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;
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章