LeetCode-華爲面試題庫做題筆記一

寫在前面

華爲面試題庫刷題第一天題目整理
歡迎訪問我的個人博客網站:flamsteed

32. 最長有效括號

給定一個只包含 ‘(’ 和 ‘)’ 的字符串,找出最長的包含有效括號的子串的長度。

一共有三種時間複雜度O(N)的解法,分別是dp,棧,和計數,我們都實現一下:

dp

dp思路:dp一位數組存放到目前這一位字符的有效子串長度,所以所有’(‘對應的位置都是0,而’)'分兩種情況:

  1. s[i]=’)’ 且 s[i-1]=’(’,則

    dp[i] = dp[i-2] + 2;

  2. s[i]=’)’ 且 s[i-1]=’)’,此時若s[i-dp[i-1]-1]=’(’,則

    dp[i] = dp[i-1] + dp[i-dp[i-1]-2] + 2;

只有這兩種情況會出現有效的括號子串,遍歷一遍之後統計最大長度即可。

代碼:

class Solution {
public:
    int longestValidParentheses(string s) {
        if(s.empty()||s.length()==1) return 0;
        int l = s.length();
        vector<int> dp(l,0);
        for(int i=1; i<l; i++){
            if(s[i]==')' && s[i-1]=='('){//情況1
                dp[i] = (i-2>=0 ? dp[i-2] : 0 ) +2;//邊界情況需要考慮,不能越界
            }
            else if(s[i]==')'&&s[i-1]==')'){//情況2
                if(i-dp[i-1]>=1 && s[i-dp[i-1]-1]=='(')
                    dp[i] = dp[i-1] + (i-dp[i-1]>=2 ? dp[i-dp[i-1]-2]:0) + 2;//同上
            }
        }
        int ans = 0;
        for(auto i : dp)
            if(i>ans) ans = i;
        return ans;
    }
};

括號匹配的題目用棧這個數據結構其實是最合適的,先將-1存放進棧頂。

  1. 對於每一個’(’,將下標放入棧中。
  2. 對於每一個’)’,彈出棧頂元素,並將現在的棧頂元素與當前下標作差,得出有效長度。如果棧已經是空的了,則插入當前下標。

代碼:

class Solution {
public:
    int longestValidParentheses(string s) {
        if(s.empty()||s.length()==1) return 0;
        int l = s.length();
        stack<int> a;
        a.push(-1);
        int maxl(0);
        for(int i=0; i<l; i++){
            if(s[i]=='('){
                a.push(i);
            }
            else{
                a.pop();
                if(a.empty())
                    a.push(i);
                else
                    if((i-a.top())>maxl) maxl = i-a.top();
            }
        }
        return maxl;
    }
};

計數法

這個方法比較tricky,只需要兩個變量left和right就能統計出答案,空間複雜度O(1)。

思路:先從左往右遍歷字符串:

  1. 遇到’(’,left加1
  2. 遇到’)’,right加1,同時進行判斷,如果此時left=right,則記錄是不是最長的長度,如果right>left,則left和right同時清零。

然後再從右往左遍歷一遍,用一樣的方法統計一遍,此時存儲的maxlength就是答案。

代碼:

class Solution {
public:
    int longestValidParentheses(string s) {
        if(s.empty()||s.length()==1) return 0;
        int l = s.length();
        int left(0), right(0),maxl(0);
        for(int i=0; i<l; i++){
            if(s[i]=='(')
                left++;
            else{
                right++;
                if(left==right){
                    if(left+right>maxl)
                        maxl = left+right;
                }
                else if(right>left){
                    left = 0;
                    right = 0;
                }
            }
        }
        left = 0;
        right = 0;
        for(int i=l-1; i>=0; i--){
            if(s[i]==')')
                right++;
            else{
                left++;
                if(left==right){
                    if(left+right>maxl)
                        maxl = left+right;
                }
                else if(left>right){
                    left = 0;
                    right = 0;
                }
            }
        }
        return maxl;
    }
};

45. 跳躍遊戲 II

給定一個非負整數數組,你最初位於數組的第一個位置。

數組中的每個元素代表你在該位置可以跳躍的最大長度。

你的目標是使用最少的跳躍次數到達數組的最後一個位置。

示例:

輸入: [2,3,1,1,4]

輸出: 2

解釋: 跳到最後一個位置的最小跳躍數是 2。從下標爲 0 跳到下標爲 1 的位置,跳 1 步,然後跳 3 步到達數組的最後一個位置。

O(N)的解法有兩種:貪心和動態規劃

貪心

每一跳都跳在下一跳最遠的位置

代碼:

class Solution {
public:
    int jump(vector<int>& nums) {
        if(nums.empty()) return 0;
        int maxp(0),end(0),step(0);
        for(int i=0; i<nums.size()-1; i++){
            maxp = max(maxp,nums[i]+i);
            if(i==end){
                end = maxp;
                step++;
            }
        }
        return step;
    }
};

dp

dp[i]記錄跳到第i位需要的最小的跳數
變量pos記錄目前跳到的位置(即dp更新到的位置)
far記錄第i位能跳到的最遠位置
此時,如果far>pos, dp[pos:far] = dp[i]+1.

代碼:

class Solution {
public:
    int jump(vector<int>& nums) {
        int pos = 1;
        int n = nums.size();
        vector<int> dp(n,0);
        int i=0;
        while(i<n){
            int far = min(n-1,i+nums[i]);//當前這一位能跳的最遠位置,如果超出範圍則返回答案
            if(pos>=n) return dp[n-1];
            while(pos<=far){//更新pos~far
                dp[pos] = dp[i]+1;
                pos++;
            }
            i++;
        }
        return dp[n-1];
    }
};

679. 24點遊戲

你有 4 張寫有 1 到 9 數字的牌。你需要判斷是否能通過 *,/,+,-,(,) 的運算得到 24。

示例 1:

輸入: [4, 1, 8, 7]

輸出: True

解釋: (8-4) * (7-1) = 24

解法:四個數字,三個符號位,126244*4=9216種可能的情況,暴搜就完事了,O(1)時間複雜度,用遞歸就行了,一個運算符一層遞歸。

代碼:

class Solution {
public:
    bool judgePoint24(vector<int>& nums) {
        double a,b,c,d;
        a = nums[0];
        b = nums[1];
        c = nums[2];
        d = nums[3];
        return judgePoint24_4(a,b,c,d);
    }

    bool judgePoint24_1(double a){
        return abs(a-24)<1e-6;
    }

    bool judgePoint24_2(double a, double b){
        return
            judgePoint24_1(a+b)||
            judgePoint24_1(a-b)||
            judgePoint24_1(a*b)||
            judgePoint24_1(a/b)||
            judgePoint24_1(b-a)||
            judgePoint24_1(b/a);
    }

    bool judgePoint24_3(double a, double b, double c){
        return 
            judgePoint24_2(a+b,c)||
            judgePoint24_2(a-b,c)||
            judgePoint24_2(a*b,c)||
            judgePoint24_2(a/b,c)||
            judgePoint24_2(b-a,c)||
            judgePoint24_2(b/a,c)||
            
            judgePoint24_2(a+c,b)||
            judgePoint24_2(a-c,b)||
            judgePoint24_2(a*c,b)||
            judgePoint24_2(a/c,b)||
            judgePoint24_2(c-a,b)||
            judgePoint24_2(c/a,b)||
            
            judgePoint24_2(b+c,a)||
            judgePoint24_2(b-c,a)||
            judgePoint24_2(b*c,a)||
            judgePoint24_2(b/c,a)||
            judgePoint24_2(c-b,a)||
            judgePoint24_2(c/b,a);
    }

    bool judgePoint24_4(double a, double b, double c, double d){
        return
            judgePoint24_3(a+b,c,d)||
            judgePoint24_3(a-b,c,d)||
            judgePoint24_3(a*b,c,d)||
            judgePoint24_3(a/b,c,d)||
            judgePoint24_3(b-a,c,d)||
            judgePoint24_3(b/a,c,d)||
            
            judgePoint24_3(a+c,b,d)||
            judgePoint24_3(a-c,b,d)||
            judgePoint24_3(a*c,b,d)||
            judgePoint24_3(a/c,b,d)||
            judgePoint24_3(c-a,b,d)||
            judgePoint24_3(c/a,b,d)||
            
            judgePoint24_3(a+d,b,c)||
            judgePoint24_3(a-d,b,c)||
            judgePoint24_3(a*d,b,c)||
            judgePoint24_3(a/d,b,c)||
            judgePoint24_3(d-a,b,c)||
            judgePoint24_3(d/a,b,c)||
            
            judgePoint24_3(b+c,a,d)||
            judgePoint24_3(b-c,a,d)||
            judgePoint24_3(b*c,a,d)||
            judgePoint24_3(b/c,a,d)||
            judgePoint24_3(c-b,a,d)||
            judgePoint24_3(c/b,a,d)||
            
            judgePoint24_3(b+d,a,c)||
            judgePoint24_3(b-d,a,c)||
            judgePoint24_3(b*d,a,c)||
            judgePoint24_3(b/d,a,c)||
            judgePoint24_3(d-b,a,c)||
            judgePoint24_3(d/b,a,c)||
            
            judgePoint24_3(c+d,a,b)||
            judgePoint24_3(c-d,a,b)||
            judgePoint24_3(c*d,a,b)||
            judgePoint24_3(c/d,a,b)||
            judgePoint24_3(d-c,a,b)||
            judgePoint24_3(d/c,a,b);
    }
};

782. 變爲棋盤

一個 N x N的 board 僅由 0 和 1 組成 。每次移動,你能任意交換兩列或是兩行的位置。

輸出將這個矩陣變爲 “棋盤” 所需的最小移動次數。“棋盤” 是指任意一格的上下左右四個方向的值均與本身不同的矩陣。如果不存在可行的變換,輸出 -1。

示例:

輸入: board = [[0,1,1,0],[0,1,1,0],[1,0,0,1],[1,0,0,1]]

輸出: 2

解釋:

一種可行的變換方式如下,從左到右:

  0110  1010  1010

  0110 --> 1010 --> 0101

  1001  0101  1010

  1001  0101  0101

第一次移動交換了第一列和第二列。

第二次移動交換了第二行和第三行。

解法:題目看起來複雜,其實只要分析清楚了就很簡單,行列是正交的,所以可以分開計算代價,且方法一樣。

判斷方法很多,我這裏用了代碼較少的一種:任意矩形的四個角的格子必須都是1或者都是0,否則一定不能變成棋盤,因爲四個角的關係通過換行和換列無法改變。

判斷完之後就計算就行了,行和列只會有兩種數列,而且是01互換的,所以只需要計算第一行和第一列的代價就行了。

計算方法:統計位置不對的格子數,然後算較小的一個(需要判斷一下邊長的奇偶情況,詳見代碼註釋)。

代碼:

class Solution {
public:
    int movesToChessboard(vector<vector<int>>& board) 
    {
        int n = board.size();
        for(int i=0;i<n;i++)//判斷四角是否相同,不同必定不能變棋盤。
        {
            for(int j=0;j<n;j++)
            {
                if((board[0][0]^board[0][j]^board[i][0]^board[i][j])==1)
                    return -1;
            }
        }
        //此時只需要判斷第一行和第一列就行了
        int row=0,col=0;
        int cntrow=0,cntcol=0;
        for(int i=0;i<n;i++)
        {
            row+=board[0][i];
            col+=board[i][0];
            if(board[0][i]!=i%2) cntrow++; //01010... 計算錯位的個數
            if(board[i][0]!=i%2) cntcol++; //01010...
        }
        if(row<n/2 || row>(n+1)/2) return -1;
        if(col<n/2 || col>(n+1)/2) return -1;//判斷1的個數是否符合要求
        int res=0;
        if(n%2==0)
        {//偶數格兩種方法需要比較出較小的
            res+=min(cntrow,n-cntrow);
            res+=min(cntcol,n-cntcol);
        }
        else
        {//奇數格的話只有一種排法,因爲只能變偶數格。
            if(cntrow%2==1)
                cntrow = n-cntrow;
            if(cntcol%2==1)
                cntcol = n-cntcol;
            res=cntrow+cntcol;
        }
        return res/2;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章