《劍指offer》-- 構建乘積陣列、求1+2+3+...+n、不用加減乘除做加法、包含min函式的棧
一、構建乘積陣列:
1、題目:
給定一個數組A[0,1,...,n-1],請構建一個數組B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。
2、解題思路:
B[i]的值可以看作下圖的矩陣中每行的乘積。
下三角用連乘可以很容求得,上三角,從下向上也是連乘。
因此我們的思路就很清晰了,先算下三角中的連乘,即我們先算出B[i]中的一部分,然後倒過來按上三角中的分佈規律,把另一部分也乘進去。
3、程式碼實現:
public class Test7 { public int[] multiply(int[] A) { int length= A.length; int[] B = new int[length]; if(length!=0){ B[0]=1; //計算下三角連乘 for(int i = 1;i<length;i++){ B[i]=B[i-1]*A[i-1]; } int temp=1; //計算上三角連乘 for(int j=length-2;j>=0;j--){ temp=temp*A[j+1]; B[j]=B[j]*temp; } } return B; } }
二、求1+2+3+...+n
1、題目:
1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷語句(A?B:C)。
2、解題思路:
利用&&的短路特性,&&就是邏輯與,邏輯與有個短路特點,前面為假,後面不計算。
3、程式碼實現:
public class Solution { public int Sum_Solution(int n) { //利用&&的短路特性,&&就是邏輯與,邏輯與有個短路特點,前面為假,後面不計算。 boolean result=true; int sum =0; result=(n>0) && ((sum=Sum_Solution(n-1))>0); sum=sum+n; return sum; } }
三、不用加減乘除做加法:
1、題目:
寫一個函式,求兩個整數之和,要求在函式體內不得使用+、-、*、/四則運算子號。
2、解題思路:
首先看十進位制是如何做的: 5+7=12,三步走:
第一步:相加各位的值,不算進位,得到2。
第二步:計算進位值,得到10. 如果這一步的進位值為0,那麼第一步得到的值就是最終結果。
第三步:重複上述兩步,只是相加的值變成上述兩步的得到的結果2和10,得到12。
同樣我們可以用三步走的方式計算二進位制值相加: 5-101,7-111 第一步:相加各位的值,不算進位,得到010,二進位制每位相加就相當於各位做異或操作,101^111。
第二步:計算進位值,得到1010,相當於各位做與操作得到101,再向左移一位得到1010,(101&111)<<1。
第三步重複上述兩步, 各位相加 010^1010=1000,進位值為100=(010&1010)<<1。 繼續重複上述兩步:1000^100 = 1100,進位值為0,跳出迴圈,1100為最終結果。
3、程式碼實現:
public class Test25 {
public int Add(int num1,int num2) {
while(num2!=0){
int temp=num1^num2;
num2=(num1&num2)<<1;
num1 = temp;
}
return num1;
}
}
四、包含min函式的棧:
1、題目:
定義棧的資料結構,請在該型別中實現一個能夠得到棧中所含最小元素的min函式(時間複雜度應為O(1))。
2、解題思路:
藉助輔助棧儲存min的大小,自定義棧結構 list 3,4,2,5,1 輔助棧 3,3,2,2,1 每入棧一次,就與輔助棧頂比較大小,如果小就入棧,如果大就入棧當前的輔助棧的棧頂元素; 當出棧時,輔助棧也要出棧,這種做法可以保證輔助棧頂一定都當前棧的最小值
3、程式碼實現:
public class Test7 {
private int size;//陣列容量
private int min=Integer.MAX_VALUE;//最小元素
private Stack<Integer> minStack = new Stack<Integer>();//輔助棧
private Integer[] elements = new Integer[10];
//資料入棧,每入棧一次,就與輔助棧頂比較大小,如果小就入棧,如果大就入棧當前的輔助棧的棧頂元素。
public void push(int node){
ensureCapacity(size+1);
elements[size++]= node;
if(node<=min){
minStack.push(node);
min=minStack.peek();
}else{
minStack.push(min);
}
}
//陣列擴容
private void ensureCapacity(int i) {
int len=elements.length;
if(size>len){
int newLen =(len*3)/2+1;//每次擴容的方式
elements=Arrays.copyOf(elements, newLen);
}
}
//元素出棧,當出棧時,輔助棧也要出棧,保證輔助棧頂一定都當前棧的最小值
private void pop(){
Integer top=top();
if(top!=null){
elements[size-1] =(Integer)null;
}
size--;
minStack.pop();
min=minStack.peek();
}
public int top(){
if(!empty()){
if(size-1>=0){
return elements[size-1];
}
}
return (Integer)null;
}
public boolean empty(){
return size == 0;
}
public int min(){
return min;
}
}