目錄
面試題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;
}