leetcode騰訊精選練習(50 題)(持續更新)

 

 

1.除自身以外數組的乘積

給定長度爲 n 的整數數組 nums,其中 n > 1,返回輸出數組 output ,其中 output[i] 等於 nums 中除 nums[i] 之外其餘各元素的乘積。

示例:

輸入: [1,2,3,4]
輸出: [24,12,8,6]
說明: 請不要使用除法,且在 O(n) 時間複雜度內完成此題。

 題解:記錄前綴積和後綴積。
 
參考代碼:
class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums)
    {
        int siz=nums.size();
        vector<int> pre(siz+1),nxt(siz+2),ans(siz);
        pre[0]=1;nxt[siz+1]=1;
        for(int i=0;i<siz;++i)
            pre[i+1]=pre[i]*nums[i];
        for(int i=siz-1;i>=0;--i)
            nxt[i+1]=nxt[i+2]*nums[i];
        
        for(int i=1;i<=siz;++i)
            ans[i-1]=pre[i-1]*nxt[i+1];
        
        return ans;
    }
};
C++

 

 2.格雷編碼

 

格雷編碼是一個二進制數字系統,在該系統中,兩個連續的數值僅有一個位數的差異。

給定一個代表編碼總位數的非負整數 n,打印其格雷編碼序列。格雷編碼序列必須以 0 開頭。

示例 1:

輸入: 2
輸出: [0,1,3,2]
解釋:
00 - 0
01 - 1
11 - 3
10 - 2

對於給定的 n,其格雷編碼序列並不唯一。
例如,[0,2,3,1] 也是一個有效的格雷編碼序列。

00 - 0
10 - 2
11 - 3
01 - 1
示例 2:

輸入: 0
輸出: [0]
解釋: 我們定義格雷編碼序列必須以 0 開頭。
  給定編碼總位數爲 n 的格雷編碼序列,其長度爲 2n。當 n = 0 時,長度爲 20 = 1。
  因此,當 n = 0 時,其格雷編碼序列爲 [0]。

題解:

對於每一層都是上一層倒着加上2^(i-1)次方。

參考代碼:

class Solution {
public:
    int qpow(int n,int m)
    {
        int res=1;
        while(m)
        {
            if(m&1) res=res*n;
            n=n*n; m>>=1;
        }
        return res;
    }
    vector<int> grayCode(int n) 
    {
        vector<int> ans;
        if(n==0) 
        {
            ans.push_back(0);
            return ans;
        }
        ans.push_back(0);
        ans.push_back(1);

        for(int i=2;i<=n;++i)
        {
            vector<int> res=ans;
            int num=qpow(2,i-1),siz=ans.size();
            for(int j=siz-1;j>=0;--j)
                ans.push_back(res[j]+num);
        }

        return ans;
    }
};
C++

 

3.二叉樹的最近公共祖先

給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。

百度百科中最近公共祖先的定義爲:“對於有根樹 T 的兩個結點 p、q,最近公共祖先表示爲一個結點 x,滿足 x 是 p、q 的祖先且 x 的深度儘可能大(一個節點也可以是它自己的祖先)。”

例如,給定如下二叉樹:  root = [3,5,1,6,2,0,8,null,null,7,4]

 

 

示例 1:

輸入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
輸出: 3
解釋: 節點 5 和節點 1 的最近公共祖先是節點 3。
示例 2:

輸入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
輸出: 5
解釋: 節點 5 和節點 4 的最近公共祖先是節點 5。因爲根據定義最近公共祖先節點可以爲節點本身。
 

說明:

所有節點的值都是唯一的。
p、q 爲不同節點且均存在於給定的二叉樹中。

題解:

  遞歸。

  兩個節點要麼是父子關係,要麼在一個root下,我們們判斷root是否爲p或q,是的話,就返回root.

然後遞歸左右子樹,如果left!=null&&right!=null則返回root.

如果left==null,則返回右子樹的遞歸結果,否則返回左子樹的遞歸結果。

參考代碼:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) 
    {
        if(root==null) return root;
        if(root==p||root==q) return root;
        TreeNode left=lowestCommonAncestor(root.left,p,q);
        TreeNode right=lowestCommonAncestor(root.right,p,q);
        
        if(left!=null && right!=null) return root;
        if(left==null) return right;
        else return left;
    }
}

Java
Java

 4.二叉搜索樹的最近公共祖先

 

給定一個二叉搜索樹, 找到該樹中兩個指定節點的最近公共祖先。

百度百科中最近公共祖先的定義爲:“對於有根樹 T 的兩個結點 p、q,最近公共祖先表示爲一個結點 x,滿足 x 是 p、q 的祖先且 x 的深度儘可能大(一個節點也可以是它自己的祖先)。”

例如,給定如下二叉搜索樹:  root = [6,2,8,0,4,7,9,null,null,3,5]

 

 

示例 1:

輸入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
輸出: 6
解釋: 節點 2 和節點 8 的最近公共祖先是 6。
示例 2:

輸入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
輸出: 2
解釋: 節點 2 和節點 4 的最近公共祖先是 2, 因爲根據定義最近公共祖先節點可以爲節點本身。
 

說明:

所有節點的值都是唯一的。
p、q 爲不同節點且均存在於給定的二叉搜索樹中。

題解:

可以用上一題的解法。但是根據二叉搜索樹的特點,左子樹的值都比我小,右子樹都比我大。

遞歸,3行代碼解決問題。

 

參考代碼:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root.val>p.val && root.val>q.val) return lowestCommonAncestor(root.left, p, q);
        if(root.val<p.val && root.val<q.val) return lowestCommonAncestor(root.right,p,q);
        return root;
    }
    
}
Java

 5.二叉樹中的最大路徑和

 

給定一個非空二叉樹,返回其最大路徑和。

本題中,路徑被定義爲一條從樹中任意節點出發,達到任意節點的序列。該路徑至少包含一個節點,且不一定經過根節點。

示例 1:

輸入: [1,2,3]

1
/ \
2 3

輸出: 6
示例 2:

輸入: [-10,9,20,null,null,15,7]

  -10
   / \
  9  20
    /  \
   15   7

輸出: 42

 

題解:

類似樹形DP,記錄每個節點的左右子樹到節點的一條鏈的最大值,和當前子樹任意兩點間的最大值即可(注意邊界條件)。

參考代碼:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    const int INF=0x3f3f3f3f;
    pair<int,int> work(TreeNode *root)
    {
        pair<int,int> p(-INF,-INF);
        if(root==NULL) return p;
        pair<int,int> l=work(root->left);
        pair<int,int> r=work(root->right);
        p.first=max(max(l.first,r.first)+root->val,root->val);
        p.second=max(max(l.second,r.second),max(root->val,max(l.first+root->val+r.first,p.first)));
        return p;
    }
    int maxPathSum(TreeNode* root) 
    {
        pair<int,int> ans=work(root);
        return ans.second;
    }
};
C++

 

6.LRU緩存機制

 

運用你所掌握的數據結構,設計和實現一個  LRU (最近最少使用) 緩存機制。它應該支持以下操作: 獲取數據 get 和 寫入數據 put 。

獲取數據 get(key) - 如果密鑰 (key) 存在於緩存中,則獲取密鑰的值(總是正數),否則返回 -1。
寫入數據 put(key, value) - 如果密鑰不存在,則寫入其數據值。當緩存容量達到上限時,它應該在寫入新數據之前刪除最近最少使用的數據值,從而爲新的數據值留出空間。

進階:

你是否可以在 O(1) 時間複雜度內完成這兩種操作?

示例:

LRUCache cache = new LRUCache( 2 /* 緩存容量 */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // 返回  1
cache.put(3, 3);    // 該操作會使得密鑰 2 作廢
cache.get(2);       // 返回 -1 (未找到)
cache.put(4, 4);    // 該操作會使得密鑰 1 作廢
cache.get(1);       // 返回 -1 (未找到)
cache.get(3);       // 返回  3
cache.get(4);       // 返回  4

題解:

按題意的來嘛,用MapStack就可以解決了。

參考代碼:

class LRUCache {
 
    Map<Integer,Integer> map ;
    Stack<Integer> stack;
    int size;
    
    public LRUCache(int capacity) {
        stack = new Stack<>();
        map = new HashMap<>(capacity);
        size = capacity;
    }
    
    public int get(int key) {
        if(!stack.contains(key)){
            return -1;
        }
        boolean flag = stack.remove(Integer.valueOf(key));
        stack.push(key);
        return map.get(key);
    }
    
    public void put(int key, int value) {
        if(stack.contains(key)){
            stack.remove(Integer.valueOf(key));
        }else{
            if(stack.size() == size){
                int count = stack.remove(0);
                map.remove(count);
            }
        }
        stack.push(key);
        map.put(key,value);
    }
}

C++
C++

 

 7.二叉搜索樹中的第K小元素

給定一個二叉搜索樹,編寫一個函數 kthSmallest 來查找其中第 k 個最小的元素。

說明:
你可以假設 k 總是有效的,1 ≤ k ≤ 二叉搜索樹元素個數。

示例 1:

輸入: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
  2
輸出: 1
示例 2:

輸入: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
輸出: 3

題解:

按照後序遍歷的順序把二叉搜索樹中的元素依次加入vector<int> ans裏面,然後輸出ans[k-1]即是第K小元素;

參考代碼:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void work(TreeNode* root,vector<int>&v)
    {
       if(root==NULL) return ;
       if(root->left) work(root->left,v);
       v.push_back(root->val);
        if(root->right) work(root->right,v);
    }

    int kthSmallest(TreeNode* root, int k) 
    {
        vector<int> ans;
        work(root,ans);
        return ans[k-1];
    }
};
C++

 

 8.NIM遊戲

你和你的朋友,兩個人一起玩 Nim 遊戲:桌子上有一堆石頭,每次你們輪流拿掉 1 - 3 塊石頭。 拿掉最後一塊石頭的人就是獲勝者。你作爲先手。

你們是聰明人,每一步都是最優解。 編寫一個函數,來判斷你是否可以在給定石頭數量的情況下贏得遊戲。

示例:

輸入: 4
輸出: false
解釋: 如果堆中有 4 塊石頭,那麼你永遠不會贏得比賽;
  因爲無論你拿走 1 塊、2 塊 還是 3 塊石頭,最後一塊石頭總是會被你的朋友拿走。

 

題解:

flag=n%4,判斷,如果flag==0則先手必敗,否則,先手必勝。

參考代碼:

class Solution {
public:
    bool canWinNim(int n) 
    {
        if(n%4) return true;
        else return false;
    }
};
C++

 

 

 

 

 

 

未完待續~

發佈了675 篇原創文章 · 獲贊 30 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章