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; } };
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; } };
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
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; } }
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; } };
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
題解:
按題意的來嘛,用Map
加Stack
就可以解決了。
參考代碼:

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++
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]; } };
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; } };
未完待續~