牛客網面試編程題總結(持續更新)

面試編程題總結(持續更新)

從頭到尾打印2020.3.31

輸入一個鏈表,按鏈表從尾到頭的順序返回一個ArrayList。
方法一:棧實現。

class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> value;//注意vector的用法
        ListNode *p=NULL;//將p指向頭結點
        p=head;
        stack<int> stk;//棧的使用方式
        while(p!=NULL){
            stk.push(p->val);//壓棧操作
            p=p->next;
        }
        while(!stk.empty()){//while循環中的條件要放.empty()
            value.push_back(stk.top());//這是動態數組vector的存數方式。
            stk.pop();
        }
        return value;
    }
};

總結:
1.這種題目逆序的還是要想到棧的先進後出的特性。
2.掌握vector data:實現了動態數組,用於元素數量變化的對象數組。
vector插入元素的形式是:data.push_back(元素);
vector清空容器:data.clear();
vector容器的長度:data.size();
訪問vector元素的方式:與訪問數組的方式相同
要特別注意vector<vector>雙重vetor->二維數組。
3.c++中棧的用法:
push(): 向棧內壓入一個成員;
pop(): 從棧頂彈出一個成員;
empty(): 如果棧爲空返回true,否則返回false;
top(): 返回棧頂,但不刪除成員;
size(): 返回棧內元素的大小;
4.特別注意結構體中value是怎麼聲明的,別一上來就是p->value;
方法二:數組翻轉

class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
			vector<int> value;
			ListNode *p=NULL;
			p = head;
			while(p!=NULL){//直接先壓如動態數組之中
				value.push_back(p->val);
				p = p ->next; 
			}
			int temp=0;
			int i = 0;
            int j=value.size()-1;
			while(i<j){//然後直接進行數組翻轉就可以了
				temp= value[i];
				value[i]=value[j];
				value[j] = temp;
				i++;
				j--; 
			}
			return value;
    }
};

這個跟上面的區別也就只有,這個方法充分利用了vetor的類數組的性質。可以,直接把vector當成一個數組,然後,直接進行代換。
方法三:遞歸思路

class Solution{
	public:
		vector<int> printListFromTailTohead(ListNode *head){
			ListNode *p  =NULL;
			p = head;
			if(p!=NULL){
				if(p->next!=NULL){//不斷的往下面遞歸,跑到最末尾。
					printListFromTailToHead(p->next);
				} 
				value.push_back(p->val);//跑到最末尾的時候,執行的就是這一句了。
			}
			return value;
		}
}; 

總結:這個方法就很奇妙了,先是不斷的判斷p->next是否爲NULL,假如真的遞歸到了最末尾,這個時候的p->val,剛好就是鏈表的最後一個元素了。這個時候,就可以將這個元素逐漸的push_back進去vector容器之中,然後返回value()就可以了。

重建二叉樹2020.3.31

題目描述
輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。

import java.util.*;
public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
    if(pre.length==0){//這是比較小心的操作,當length==0時,直接return null
	     return null;
	 }
	int rootVal = pre[0];//首先,根據先序遍歷拿到根節點
	if(pre.length==1)
		return new TreeNode(rootVal);//這是返回一課樹的表現
	TreeNode root = new TreeNode(rootVal);//新建一棵樹,開始裝左右樹。
	int rootIndex = 0;//
	for(int i=0;i<in.length;i++){//從這個for循環中拿到中序遍歷的根節點的地方
		if(rootVal==in[i]){
			rootIndex = i;
			break;
		}
	}
	root.left = reConstructBinaryTree(Arrays.copyOfRange(pre,1,rootIndex+1),Arrays.copyOfRange(in,0,rootIndex));//這個地方就只能靠遞歸建樹了。給出左子樹中,先序,中序遍歷的序列
	root.right = reConstructBinaryTree(Arrays.copyOfRange(pre,rootIndex+1,pre.length),Arrays.copyOfRange(in,rootIndex+1,in.length));//這個地方就只能靠遞歸建樹了。給出右子樹中,先序,中序遍歷的序列
    return root;//到最後,你就會因爲給出的序列只有一個節點,跳出這個遞歸
    }
}

總結:遞歸,肯定非常重要的是遞歸出來的條件。這時,要注意,判斷說結點數爲0和結點數爲1的情況。然後,找到中序遍歷序列的根節點的位置。
接下來,就可以使用遞歸。把root的左子樹的範圍給進行,遞歸建樹。用到Arrays.copyOfRange數組複製。注意要先import java.util.*,然後再使用這個函數。Arrays.copyOfRange(T[ ] original,int from,int to)將一個原始的數組original,從下標from開始複製,複製到上標to,生成一個新的數組。注意這裏包括下標from,不包括上標to。
Java複製數組的四種方法:arraycopy()方法、clone() 方法、copyOf()和copyOfRange()方法。

Arrays.copyOf(dataType[] srcArray,int length);
Arrays.copyOfRange(dataType[] srcArray,int startIndex,int endIndex)
System.arraycopy(dataType[] srcArray,int srcIndex,int destArray,int destIndex,int length)
array_name.clone()

用兩個棧實現隊列2020.4.2

class Solution
{
public:
    void push(int node) {
        stack1.push(node);//先入棧1
    }

    int pop() {
        int a;
        if(stack2.empty()){
            while(!stack1.empty()){
               a = stack1.top();//你要先拿到這個值,再push,或pop,不然,一旦不拿着,直接push或pop就沒了
               stack2.push(a);
                stack1.pop();
            }
        }
        a  = stack2.top();
        stack2.pop();
        return a;
    }

private:
    stack<int> stack1;
    stack<int> stack2;
};

總結:整體的思路其實很簡單,就是在
入隊列:直接壓棧1
出隊列:先判斷棧2是否爲空,若爲空,就得把棧1 的所有元素搞到棧2,讓元素把順序反過來。然後,再開始真正的從棧2出元素。不然,或棧2 不爲空的話,就直接從棧2出元素就好了。你畫個圖,也許就能明白了。
但要注意,我代碼中的那一點。出棧時,一定先用stack.top(),拿到要出棧的元素,不然,你壓棧的時候,就沒辦法壓了。

旋轉數組的最小數字2020.4.2

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
    //二分查找使用時,要把0個元素和1個元素的情況都要考慮到。
        int length_vector=rotateArray.size();//首先,一定要先考慮特殊情況,length=0的情況
        if(length_vector==0)
             return 0;
        int low = 0;//二分查找的固定套路
        int high = length_vector-1;
        if(low==high)//只有一個元素時的情況。
            return rotateArray[low];
        while(low<high){
            if(rotateArray[low]<rotateArray[high])//這個if考慮的是旋轉後的數組是有序的時候
                return rotateArray[low];
            if(high==low+1)//這個考慮的是當只有兩個元素得到時候
                return rotateArray[high];
            int mid = (high+low)/2;
            if(rotateArray[low]>=rotateArray[mid]&&rotateArray[high]>=rotateArray[mid]){//這個if考慮的是,數組中出現相同元素的時候,只能採用順序查找了。
                int index = low;
                for(int i=low+1;i<=high;i++){
                    if(rotateArray[index]>rotateArray[i])
                        index = i;//把最小元素的下標就可以找出來了。
                }
                return rotateArray[index];
            }
            if(rotateArray[low]<rotateArray[mid])//二分查找的經典方式。
                low = mid+1;
            else if(rotateArray[high]>rotateArray[mid])   //最小元素在low~mid之間
                high=mid-1;  
                
        }
        return -1;
    }
};

總結:當然,這題也可以用順序查找,不過就是查找一個最小值,但要注意,這裏要考察的是二分,用二分的時間複雜度爲O(nlogn),順序就只是O(n)了。

質因數的統計2020.4.3

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int a[100006];
int main(){
	int n;
	cin>>n;
	int ans = 0;
	for(int i=1;i<=n;i++){//把這個範圍內要弄的數放在數組中比較方便
		a[i]=i;
	}
	for(int i=2;i<=n;i++){//確保從a[2]開始,因爲質因數的分解從2開始數。
		if(a[i]>1){//這是循環的破出條件。
			for(int j=2;j<=sqrt(n);j++){//注意這裏的sqrt很重要,減少了很多數的比較
				while(a[i]%j==0){//不斷的除,就能得到想要的那個質數。
					a[i] = a[i]/j;
					ans++;
				//	cout<<ans<<endl;
				}
			}
		} 
	}	
	for(int i=1;i<=n;i++){//這個地方應該只是確保把本來就是質數的那一個
	//也就是上面的循環沒有處理的那個算進來,不然,就會少了本來就是質數的那一份。
		if(a[i]>1)
			ans++;
	}
	cout<<ans;
	return 0;
} 

總結:基本把思路已經寫在代碼中了,這個代碼已經很容易理解了。

跳臺階2020.4.4

題目描述
一隻青蛙一次可以跳上1級臺階,也可以跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法(先後次序不同算不同的結果)。

class Solution {
public:
    int jumpFloor(int number) {
        if(number<1){
            return 0;
        }
        else if(number==1){
            return 1;
        }
        else if(number==2){
            return 2;
        }
        else{
            int result =0;
            int pre1 =0;
            int pre2 = 1;
            for(int i=1;i<=number;i++){
                result  = pre1+pre2;
                pre1 = pre2;
                pre2 = result;
            }
            return result;
        }
    }
};

總結:仔細研究一下,其實這個題目也是一個斐波拉契數列而已。遞歸也可以,不過遞歸太浪費資源,很多時候,這種題目是一般過不了的。

二進制中的個數2020.4.7

#include<cstdio>
#include<iostream>
using namespace std;
int NumberOf1_low(int n) {
        int count = 0;
        int flag = 1;
        while (flag != 0) {
            if ((n & flag) != 0) {
                count++;
                
            }
            flag = flag << 1;//將flag的1進行移位,逐位與n進行相比。
            //注意,若對n進行移位,負數會導致死循環,因爲對n進行右移時,
            //是補1的,所以不能那麼做。
        }
        return count;
    }
int main(){
	int n;
	cin>>n;
	cout<<NumberOf1_low(n);
	return 0; 
}

總結:我可能還是做的太少,一開始想到只有是將這個二進制給表示出來,逐漸的循環,從而得到1的個數。沒想到,在n於1進行與操作的時候,他們之間的進制已經自動轉換成爲二進制了。

數值的整數次方

public class Solution {
    public double Power(double base, int exponent) {
       int n=exponent;
       //首先要區分好情況。
       if(exponent<0){
            if(base==0)
                throw new RuntimeException("分母不能爲0");
             exponent = -exponent;
       }
       else if(exponent==0){
           return 1;    
       }
       double res =1,cur =base;
       while(exponent!=0){//這個是快速冪的解法,也就是把指數分解成二進制,然後,逐步的乘
           if((exponent&1)==1)//如果這個位爲1,那就是要乘了。
                res*=cur;
           cur*=cur;//不管上面這個If是否有執行,那個指數肯定是要翻倍的,比較是2的多少次方。
           exponent=exponent>>1;//右移一位,逐漸看一下指數的二進制形式的各個位。
       }
       if(n>=0)//判斷當時的指數是正數還是負數。
           return res;
        else{
            return 1/res;
        }
    } 
}

總結:這個題目歸根到底還是用空間換取時間的一道題目,因爲直接乘的話,確實花費的計算的時間太大了。還是比較值得掌握的一道題目的。

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