10.11 牛客《劍指offer》 T1-12
T1 二維部分有序數組查找 ☆
在一個二維數組中(每個一維數組的長度相同),每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數。
由於矩陣部分有序,向上數字遞減,向右數字遞增:
- 目標數字只會出現在行首小於該數的行中
- 遍歷行i ,若列j 對應的元素大於目標,那麼在前 i-1 行,目標只會出現在 j列及以後。
因此,可以從左下角開始查找。目標比左下角數字小時,上移;當要目標比左下角數字大時,右移。
搜索的路線是階梯狀,複雜度爲O(行數+列數)。
class Solution {
public:
bool Find(int target, vector<vector<int> > array) {
int nrows = array.size();
int ncols = array[0].size();
int i = nrows - 1, j = 0;
while(i >= 0 && j < ncols){
if(array[i][j] == target) return true;
else if(array[i][j]< target ){
j++;
}else i--;
}
return false;
}
};
WA警告:
之前的錯誤代碼版本如下,由於判斷條件中的 && 寫成 , 造成段錯誤(數組越界訪問):
class Solution {
public:
bool Find(int target, vector<vector<int> > array) {
int nrows = array.size();
int ncols = array[0].size();
if( ncols == 0 || nrows == 0) return false;
for(int i = nrows - 1, j = 0; i >= 0, j < ncols; i--){
if( array[i][j] == target )
return true;
if( array[i][j] < target){
i++;
j++;
}
}
return false;
}
};
T2 字符串字符不等長替換 - 從後往前
請實現一個函數,將一個字符串中的每個空格替換成“%20”。例如,當字符串爲We Are Happy.則經過替換之後的字符串爲We%20Are%20Happy。
實現統計好空格數目從後往前寫。問題是 str 所指的空間會內存泄露吧?
注意補上 ‘\0’(應該不會有憨憨如我補了一個’\n’…
T3 返回鏈表的反序 vector
輸入一個鏈表,按鏈表從尾到頭的順序返回一個ArrayList。
遞歸或者對正序 vector reverse。
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<int> rst;
if(head == NULL)return rst;
rst = printListFromTailToHead(head->next);
rst.emplace_back(head->val);
return rst;
}
};
//----------------------vv---------------------------------
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<int> rst;
ListNode* pNode = head;
while(pNode!=NULL){
rst.emplace_back(pNode->val);
pNode=pNode->next;
}
reverse(rst.begin(),rst.end());
return rst;
}
};
T4 重建二叉樹
輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。
遞歸建樹。注意遞歸出口,當有 0 或一個節點時直接返回。
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
if(pre.size()==0)
return NULL;
if(pre.size()==1)
return new TreeNode(pre[0]);
TreeNode* root = new TreeNode(pre[0]);
int lenl =0, lenr = 0,len = vin.size();
while(lenl<len && vin[lenl]!= pre[0])
lenl++;
vector<int> npre,nvin;
npre = vector<int>(pre.begin()+1,pre.begin()+1+lenl);
nvin = vector<int>(vin.begin(),vin.begin()+lenl);
root->left = reConstructBinaryTree(npre,nvin);
npre = vector<int>(pre.begin()+1+lenl,pre.end());
nvin = vector<int>(vin.begin()+lenl+1,vin.end());
root->right = reConstructBinaryTree(npre,nvin);
return root;
}
};
T5 兩個棧模擬隊列
用兩個棧來實現一個隊列,完成隊列的Push和Pop操作。 隊列中的元素爲int類型。
棧1接收入隊列元素,棧2存儲出隊列元素,當棧2空時,把棧1元素倒到棧2中。
class Solution
{
public:
void push(int node) {
stack1.push(node);
}
int pop() {
if(stack2.size()==0){
while(!stack1.empty()){
int x=stack1.top();
stack1.pop();
stack2.push(x);
}
}
int x=stack2.top();
stack2.pop();
return x;
}
private:
stack<int> stack1;
stack<int> stack2;
};
T6 旋轉數組中的最小元素 - 二分或暴力 ☆
把一個數組最開始的若干個元素搬到數組的末尾,我們稱之爲數組的旋轉。
輸入一個非遞減排序的數組的一個旋轉,輸出旋轉數組的最小元素。
例如數組{3,4,5,1,2}爲{1,2,3,4,5}的一個旋轉,該數組的最小值爲1。
NOTE:給出的所有元素都大於0,若數組大小爲0,請返回0。
由於旋轉後,數組前半段非減,後半段非減,所以從後往前遍歷,轉折點一定是最小元素。如果沒有轉折點,那麼所有元素都相等。(像這樣 ··``…·
但是這個轉折點可以試着二分。由於轉折處的右側是最小元素,所以選擇儘量讓區間右端點落在最小元素上。那麼:
- array[mid] > array[high]
出現這種情況的array類似[3,4,5,6,0,1,2],此時最小數字一定在mid的右邊。
low = mid + 1 - array[mid] == array[high]:
出現這種情況的array類似 [1,0,1,1,1] 或者[1,1,1,0,1],此時最小數字不好判斷在mid左邊還是右邊,這時只好一步步縮小區間。
high = high - 1 - array[mid] < array[high]:
出現這種情況的array類似[2,2,3,4,5,6,6],此時最小數字一定就是array[mid]或者在mid的左邊。因爲右邊必然都是遞增的。
high = mid
注意,考慮最後區間長爲2或爲3 的情況,上述的收斂方式都會使得 low 和 high 最終都指向最小元素。
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
if(rotateArray.size()==0)
return 0;
int lo =0, hi = rotateArray.size()-1,mid;
while(lo< hi){
mid = lo+((hi-lo)>>1);
if(rotateArray[mid]>rotateArray[hi])
lo=mid+1;
else if (rotateArray[mid] == rotateArray[hi])
hi-=1;
else hi=mid;
}
return rotateArray[hi];
}
};
T7 - 10 斐波那契數列 - 遞推遞歸 - 兩變量寫法
T7:大家都知道斐波那契數列,現在要求輸入一個整數n,請你輸出斐波那契數列的第n項(從0開始,第0項爲0)。 n<=39。
class Solution {
public:
int Fibonacci(int n) {
if(n==0) return 0;
if(n==1) return 1;
if(n==2) return 1;
return Fibonacci(n-1)+Fibonacci(n-2);
}
};
T8:一隻青蛙一次可以跳上1級臺階,也可以跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法(先後次序不同算不同的結果)。
// 兩變量
class Solution {
public:
int jumpFloor(int number) {
if(number==0)return 1;
if(number==1)return 1;
if(number==2)return 2;
int f=1,g=2;
number-=2;
while(number--){
g=f+g;
f=g-f;
}
return g;
}
};
T9:一隻青蛙一次可以跳上1級臺階,也可以跳上2級……它也可以跳上n級。求該青蛙跳上一個n級的臺階總共有多少種跳法。
// dp
class Solution {
public:
int jumpFloorII(const int number) {
int** dp=new int*[number+10];
for(int i=0;i<number+10;i++){
dp[i]=new int[number+10];
}
memset(dp,0,sizeof dp);
for(int i=1;i<=number;i++){
dp[1][i]=1;
}
// dp[i][j] 用i步跳上臺階j
for(int i=2;i<=number;i++){
for(int j=i;j<=number;j++){
for(int k=i-1;k<j;k++){
dp[i][j]+=dp[i-1][k];
}
}
}
int ans=0;
for(int i=1;i<=number;i++){
ans+=dp[i][number];
}
return ans;// 返回的變量打錯,不可原諒,,
}
};
T10:我們可以用2*1的小矩形橫着或者豎着去覆蓋更大的矩形。請問用n個2*1的小矩形無重疊地覆蓋一個2*n的大矩形,總共有多少種方法?
類似於前面幾題。
class Solution {
public:
int rectCover(int number) {
if(number==0) return 0;
if(number==1) return 1;
if(number==2) return 2;
int f=1,g=2;
number-=2;
while(number--){
g=f+g;
f=g-f;
}
return g;
}
};
T11 二進制中 1 的個數
輸入一個整數,輸出該數二進制表示中1的個數。其中負數用補碼錶示。
注意對於負數,右移一位會補 1 而非補零。
// 1. 去掉符號位 1
class Solution {
public:
int NumberOf1(int n) {
int cnt=0;
if(n<0) {
n &=0x7fffffff;
cnt++;
}
while(n){
cnt+=(n&1);
n>>=1;
}
return cnt;
}
};
// 2. 轉爲 unsigned int
class Solution {
public:
int NumberOf1(int n) {
unsigned int nn=n;
int cnt=0;
while(nn){
cnt+=(nn&1);
nn>>=1;
}
return cnt;
}
};
// 3. 每次 n&(n-1) 將從右邊起的第一個 1 變爲 0
public class Solution {
public int NumberOf1(int n) {
int count = 0;
while(n!= 0){
count++;
n = n & (n - 1);
}
return count;
}
}
T12 數值的整數次方 - 縝密 - 基數可能爲負數
給定一個double類型的浮點數 base 和 int 類型的整數exponent。求base的exponent次方。 保證base和exponent不同時爲0
class Solution {
public:
double Power(double base, int exponent) {
double ans=1;
bool neg= false;
else if(exponent<0){
neg=true;
exponent=-exponent;
}
for( ; exponent; base*=base,exponent/=2){
if(exponent&1){
ans*=base;
}
}
return neg?1/ans:ans;
}
};