第一次模擬
第一題 字符串中的單詞個數(簡單)
統計字符串中的單詞個數,這裏的單詞指的是連續的不是空格的字符。css
請注意,你能夠假定字符串裏不包括任何不可打印的字符。node
示例:算法
輸入: "Hello, my name is John" 輸出: 5


1 class Solution { 2 public: 3 int countSegments(string s) { 4 int len=s.length(); 5 int ans=0,i=0; 6 if(len==0) return 0; 7 while(i<len) 8 { 9 while(s[i]==' ' && i<len) ++i; 10 11 if(s[i]!=' ' && i<len) 12 { 13 while(s[i]!=' ' && i<len) ++i; 14 ans++; 15 } 16 } 17 return ans; 18 } 19 };
第二題 兩數相加 II(中等)
給定兩個非空鏈表來表明兩個非負整數。數字最高位位於鏈表開始位置。它們的每一個節點只存儲單個數字。將這兩數相加會返回一個新的鏈表。數組
你能夠假設除了數字 0 以外,這兩個數字都不會以零開頭。app
進階:ide
若是輸入鏈表不能修改該如何處理?換句話說,你不能對列表中的節點進行翻轉。函數
示例:學習
輸入: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4) 輸出: 7 -> 8 -> 0 -> 7
題解:spa
將兩個鏈表反轉以後,按照位置加便可,設置一個進位add;.net
參考代碼:


1 /** 2 * Definition for singly-linked list. 3 * struct ListNode { 4 * int val; 5 * ListNode *next; 6 * ListNode(int x) : val(x), next(NULL) {} 7 * }; 8 */ 9 class Solution { 10 public: 11 ListNode* addTwoNumbers(ListNode *l1, ListNode *l2) { 12 ListNode* tmp = new ListNode(-1), *cur = tmp; 13 int cnt = 0; 14 l1 = reverseList(l1); 15 l2 = reverseList(l2); 16 while (l1 || l2) { 17 int val1 = l1 ? l1 -> val : 0; 18 int val2 = l2 ? l2 -> val : 0; 19 int sum = val1 + val2 + cnt; 20 cnt = sum / 10; 21 cur -> next = new ListNode(sum % 10); 22 cur = cur -> next; 23 if (l1) l1 = l1 -> next; 24 if (l2) l2 = l2 -> next; 25 } 26 if (cnt) cur -> next = new ListNode(1); 27 return reverseList(tmp -> next); 28 } 29 30 ListNode* reverseList(ListNode *head) { 31 if (!head) return head; 32 ListNode* dummy = new ListNode(-1); 33 dummy -> next = head; 34 ListNode* cur = head; 35 while (cur -> next) { 36 ListNode *tmp = cur -> next; 37 cur -> next = tmp -> next; 38 tmp -> next = dummy -> next; 39 dummy -> next = tmp; 40 } 41 return dummy -> next; 42 } 43 };
第三題 最小區間(困難)
你有 k
個升序排列的整數數組。找到一個最小區間,使得 k
個列表中的每一個列表至少有一個數包含在其中。
咱們定義若是 b-a < d-c
或者在 b-a == d-c
時 a < c
,則區間 [a,b] 比 [c,d] 小。
示例 1:
輸入:[[4,10,15,24,26], [0,9,12,20], [5,18,22,30]] 輸出: [20,24] 解釋: 列表 1:[4, 10, 15, 24, 26],24 在區間 [20,24] 中。 列表 2:[0, 9, 12, 20],20 在區間 [20,24] 中。 列表 3:[5, 18, 22, 30],22 在區間 [20,24] 中。
注意:
- 給定的列表可能包含重複元素,因此在這裏升序表示 >= 。
- 1 <=
k
<= 3500 - -105 <=
元素的值
<= 105 - 對於使用Java的用戶,請注意傳入類型已修改成List<List<Integer>>。重置代碼模板後能夠看到這項改動。
題解:
使用優先隊列(小頂堆),首先將k個數組的第一個元素加入隊列,並記錄最大值。而後用最大值-堆頂元素(即最小值)去更新答案。而後把堆頂的元素所在數組的指針向後移,若是已經到達數組末尾則跳出循環,輸出答案。
參考代碼:


1 class node { 2 public: 3 int row; 4 int col; 5 int val; 6 node(int ir, int ic, int iv) { 7 row = ir; 8 col = ic; 9 val = iv; 10 } 11 }; 12 13 class cmp { 14 public: 15 bool operator() (const node &lhs, const node &rhs) { 16 return lhs.val > rhs.val; 17 } 18 }; 19 20 class Solution { 21 public: 22 vector<int> smallestRange(vector<vector<int>>& nums) { 23 priority_queue<node, vector<node>, cmp> pqn; 24 const int k = nums.size(); 25 int max = -INT_MAX; 26 for (int i = 0; i < k; i++) { 27 if (nums[i][0] > max) { 28 max = nums[i][0]; 29 } 30 pqn.push(node(i, 0, nums[i][0])); 31 } 32 int lret = 0; 33 int rret = INT_MAX; 34 bool has_next = true; 35 do { 36 auto min = pqn.top(); 37 pqn.pop(); 38 //cout << min.val << "," << max << endl; 39 if (max - min.val < rret - lret) { 40 lret = min.val; 41 rret = max; 42 } 43 min.col++; 44 if (min.col >= nums[min.row].size()) { 45 has_next = false; 46 } else { 47 min.val = nums[min.row][min.col]; 48 if (max < min.val) 49 max = min.val; 50 pqn.push(min); 51 } 52 } while(has_next); 53 return {lret, rret}; 54 } 55 };
第二次模擬
第一題 重複的DNA序列(中等)
全部 DNA 都由一系列縮寫爲 A,C,G 和 T 的核苷酸組成,例如:「ACGAATTCCG」。在研究 DNA 時,識別 DNA 中的重複序列有時會對研究很是有幫助。
編寫一個函數來查找 DNA 分子中全部出現超過一次的 10 個字母長的序列(子串)。
示例:
輸入:s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT" 輸出:["AAAAACCCCC", "CCCCCAAAAA"]
題解:bitset; 由於只有4個字符,因此能夠把字符對應爲數字。而後兩個bitset,判斷是否出現過,和是否插入到答案集合。
參考代碼:


1 class Solution { 2 public: 3 int charToBit(char c){ 4 switch (c){ 5 case 'A': return 0; 6 case 'G': return 1; 7 case 'C': return 2; 8 case 'T': return 3; 9 } 10 return -1; // never happened 11 } 12 13 vector<string> findRepeatedDnaSequences(string s) { 14 vector<string> res; 15 if(s.size() < 10) return res; 16 bitset<1<<20> S1; 17 bitset<1<<20> S2; // to avoid dulplication 18 //init 19 int val = 0; 20 for(int i=0;i<10;i++){ 21 val = val << 2 | charToBit(s[i]); 22 } 23 S1.set(val); 24 int mask = (1 << 20) - 1; 25 for(int i=10;i<s.size();i++){ 26 val = ((val << 2) & mask) | charToBit(s[i]); 27 if(S1[val]) { 28 if (!S2[val]) { 29 res.push_back(s.substr(i - 9, 10)); 30 S2.set(val); 31 } 32 } 33 else{ 34 S1.set(val); 35 } 36 } 37 return res; 38 } 39 };
第二題 分割數組的最大值(困難)
給定一個非負整數數組和一個整數 m,你須要將這個數組分紅 m 個非空的連續子數組。設計一個算法使得這 m 個子數組各自和的最大值最小。
注意:
數組長度 n 知足如下條件:
- 1 ≤ n ≤ 1000
- 1 ≤ m ≤ min(50, n)
示例:
輸入: nums = [7,2,5,10,8] m = 2 輸出: 18 解釋: 一共有四種方法將nums分割爲2個子數組。 其中最好的方式是將其分爲[7,2,5] 和 [10,8], 由於此時這兩個子數組各自的和的最大值爲18,在全部狀況中最小
題解:動態規劃。dp[i][j]:表示前i個數分紅j個區間所能獲得的最大值的最小值。
轉移方程爲:dp[i][j]=min(dp[i][j],max(dp[k][j-1],pre[i]-pre[j]));
參考代碼:


1 class Solution { 2 public: 3 int splitArray(vector<int>& nums, int m) 4 { 5 int n=nums.size(); 6 unsigned long long dp[n+2][m+2]; 7 memset(dp,127,sizeof(dp)); 8 unsigned long long sum[n+3]; 9 sum[0]=dp[0][0]=0; 10 for(int i=1;i<=n;i++) 11 sum[i]=sum[i-1]+nums[i-1]; 12 for(int i=1;i<=n;i++) 13 { 14 for(int j=1;j<=m;j++) 15 { 16 for(int k=0;k<i;k++) 17 { 18 dp[i][j]=min(dp[i][j],max(dp[k][j-1],sum[i]-sum[k])); 19 } 20 } 21 } 22 return dp[n][m]; 23 } 24 };
第三題 樹中距離之和(困難)
給定一個無向、連通的樹。樹中有 N
個標記爲 0...N-1
的節點以及 N-1
條邊 。
第 i
條邊鏈接節點 edges[i][0]
和 edges[i][1]
。
返回一個表示節點 i
與其餘全部節點距離之和的列表 ans
。
示例 1:
輸入: N = 6, edges = [[0,1],[0,2],[2,3],[2,4],[2,5]] 輸出: [8,12,6,10,10,10] 解釋: 以下爲給定的樹的示意圖: 0 / \ 1 2 /|\ 3 4 5 咱們能夠計算出 dist(0,1) + dist(0,2) + dist(0,3) + dist(0,4) + dist(0,5) 也就是 1 + 1 + 2 + 2 + 2 = 8。 所以,answer[0] = 8,以此類
題解:兩遍dfs。
第一次dfs出以0節點爲根的每一個節點到根節點的間距離和每一個節點的子節點數量。
第二次dfs,從根開始,它的子節點到全部節點的距離= ans[root] (當前節點的父節點到全部節點的距離) - count[i](當前節點的子節點的數量,包含本身)+ size (全部節點的數量) -count[i];
參考代碼:


1 class Solution { 2 public: 3 vector<unordered_set<int>> tree; 4 vector<int> res, count; 5 6 vector<int> sumOfDistancesInTree(int N, vector<vector<int>>& edges) { 7 tree.resize(N); 8 res.assign(N, 0); 9 count.assign(N, 1); 10 for (auto e : edges) { 11 tree[e[0]].insert(e[1]); 12 tree[e[1]].insert(e[0]); 13 } 14 dfs(0, -1); 15 dfs2(0, -1); 16 return res; 17 18 } 19 20 void dfs(int root, int pre) { 21 for (auto i : tree[root]) { 22 if (i == pre) continue; 23 dfs(i, root); 24 count[root] += count[i]; 25 res[root] += res[i] + count[i]; 26 } 27 } 28 29 void dfs2(int root, int pre) { 30 for (auto i : tree[root]) { 31 if (i == pre) continue; 32 res[i] = res[root] - count[i] + count.size() - count[i]; 33 dfs2(i, root); 34 } 35 } 36 };
第三次模擬
第一題 最大連續1的個數 III
給定一個由若干 0
和 1
組成的數組 A
,咱們最多能夠將 K
個值從 0 變成 1 。
返回僅包含 1 的最長(連續)子數組的長度。
示例 1:
輸入:A = [1,1,1,0,0,0,1,1,1,1,0], K = 2 輸出:6 解釋: [1,1,1,0,0,1,1,1,1,1,1] 粗體數字從 0 翻轉到 1,最長的子數組長度爲 6。
示例 2:
輸入:A = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], K = 3 輸出:10 解釋: [0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1] 粗體數字從 0 翻轉到 1,最長的子數組長度爲 10。
提示:
1 <= A.length <= 20000
0 <= K <= A.length
A[i]
爲0
或1
題解:雙指針。保證l到r之間的0的數量爲k便可,每次移動r和l記錄r-l的最大值。
參考代碼:


1 class Solution { 2 public: 3 int longestOnes(vector<int>& A, int K) { 4 int left = 0; 5 int right = 0; 6 int count = 0; 7 int count_all = 0; 8 while(right < A.size()) 9 { 10 while(right < A.size()) 11 { 12 if(K == 0) 13 { 14 while(right < A.size() && left == right && A[left] == 0) 15 { 16 left++; 17 right++; 18 } 19 if(right == A.size()) 20 break; 21 } 22 if(A[right] == 0) 23 count++; 24 right++; 25 while(right < A.size() && A[right] == 1) 26 right++; 27 if(count >= K) 28 break; 29 } 30 count_all = max(count_all,right-left); 31 while(left < A.size()&&count >=K) 32 { 33 if(A[left] == 0) 34 count--; 35 left++; 36 } 37 } 38 return count_all; 39 } 40 41 };
第二題 島嶼的最大面積
給定一個包含了一些 0 和 1的非空二維數組 grid
, 一個 島嶼 是由四個方向 (水平或垂直) 的 1
(表明土地) 構成的組合。你能夠假設二維矩陣的四個邊緣都被水包圍着。
找到給定的二維數組中最大的島嶼面積。(若是沒有島嶼,則返回面積爲0。)
示例 1:
[[0,0,1,0,0,0,0,1,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,0,0,0], [0,1,1,0,1,0,0,0,0,0,0,0,0], [0,1,0,0,1,1,0,0,1,0,1,0,0], [0,1,0,0,1,1,0,0,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,1,0,0], [0,0,0,0,0,0,0,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,0,0,0,0]]
對於上面這個給定矩陣應返回 6
。注意答案不該該是11,由於島嶼只能包含水平或垂直的四個方向的‘1’。
示例 2:
[[0,0,0,0,0,0,0,0]]
對於上面這個給定的矩陣, 返回 0
。
注意: 給定的矩陣grid
的長度和寬度都不超過 50。
題解:
典型的dfs求聯通快大小。
參考代碼:


1 class Solution { 2 public: 3 int dfs(vector<vector<int>>& grid,int ii,int j) 4 { 5 int n=grid.size();int m=grid[0].size(); 6 int dx[4]={0,0,1,-1}; 7 int dy[4]={1,-1,0,0}; 8 grid[ii][j]=0;//把訪問過的1變爲0 9 int sum=1; 10 11 for(int i=0;i<4;i++) 12 { 13 int x=ii+dx[i]; 14 int y=j+dy[i]; 15 if(x>=0&&x<n&&y>=0&&y<m&&grid[x][y]==1) 16 sum+=dfs(grid,x,y); 17 } 18 return sum; 19 } 20 int maxAreaOfIsland(vector<vector<int>>& grid) 21 { 22 int n=grid.size(); 23 if(n==0) return 0; 24 int m=grid[0].size(); 25 int ans=0; 26 for(int i=0;i<n;i++) 27 { 28 for(int j=0;j<m;j++) 29 { 30 if(grid[i][j]==1) 31 ans=max(dfs(grid,i,j),ans); 32 } 33 } 34 return ans; 35 } 36 };
第三題 求根到葉子節點數字之和
給定一個二叉樹,它的每一個結點都存放一個 0-9
的數字,每條從根到葉子節點的路徑都表明一個數字。
例如,從根到葉子節點路徑 1->2->3
表明數字 123
。
計算從根到葉子節點生成的全部數字之和。
說明: 葉子節點是指沒有子節點的節點。
示例 1:
輸入: [1,2,3] 1 / \ 2 3 輸出: 25 解釋: 從根到葉子節點路徑 表明數字 . 從根到葉子節點路徑 表明數字 . 所以,數字總和 = 12 + 13 = .1->2121->31325
示例 2:
輸入: [4,9,0,5,1] 4 / \ 9 0 / \ 5 1 輸出: 1026 解釋: 從根到葉子節點路徑 表明數字 495. 從根到葉子節點路徑 表明數字 491. 從根到葉子節點路徑 表明數字 40. 所以,數字總和 = 495 + 491 + 40 = .4->9->54->9->14->01026
題解:dfs便可。
參考代碼:


1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 private: 12 int ans=0; 13 public: 14 15 void dfs(TreeNode* root,int num) 16 { 17 if(root->left==NULL && root->right==NULL) 18 ans=ans+num; 19 else 20 { 21 if(root->left) dfs(root->left,num*10+root->left->val); 22 if(root->right) dfs(root->right,num*10+root->right->val); 23 } 24 } 25 int sumNumbers(TreeNode* root) 26 { 27 if(root==NULL) return 0; 28 dfs(root,root->val); 29 return ans; 30 } 31 };
第四次模擬
第一題 用戶分組
有 n
位用戶參加活動,他們的 ID 從 0
到 n - 1
,每位用戶都 剛好 屬於某一用戶組。給你一個長度爲 n
的數組 groupSizes
,其中包含每位用戶所處的用戶組的大小,請你返回用戶分組狀況(存在的用戶組以及每一個組中用戶的 ID)。
你能夠任何順序返回解決方案,ID 的順序也不受限制。此外,題目給出的數據保證至少存在一種解決方案。
示例 1:
輸入:groupSizes = [3,3,3,3,3,1,3] 輸出:[[5],[0,1,2],[3,4,6]] 解釋: 其餘可能的解決方案有 [[2,1,6],[5],[0,4,3]] 和 [[5],[0,6,2],[4,3,1]]。
示例 2:
輸入:groupSizes = [2,1,3,3,3,2] 輸出:[[1],[0,5],[2,3,4]]
提示:
groupSizes.length == n
1 <= n <= 500
1 <= groupSizes[i] <= n
題解:
把數字和下標存到pair裏面,而後按照數字大小排序。而後每次取第一個數字的大小爲長度len,從該數字向後的len個數字分爲一個組。
參考代碼:


1 class Solution { 2 public: 3 vector<vector<int>> groupThePeople(vector<int>& g) 4 { 5 vector<vector<int>> ans; 6 int n=g.size(); 7 if(n==0) return ans; 8 pair<int,int> pi[n]; 9 for(int i=0;i<n;++i) 10 pi[i].first=g[i],pi[i].second=i; 11 sort(pi,pi+n); 12 int len=0; 13 while(len<n) 14 { 15 vector<int> res; 16 int num=pi[len].first; 17 while(num--) 18 { 19 res.push_back(pi[len].second); 20 len++; 21 } 22 ans.push_back(res); 23 } 24 25 return ans; 26 } 27 };
第二題 Excel表列名稱
給定一個正整數,返回它在 Excel 表中相對應的列名稱。
例如,
1 -> A 2 -> B 3 -> C ... 26 -> Z 27 -> AA 28 -> AB ...
示例 1:
輸入: 1 輸出: "A"
示例 2:
輸入: 28 輸出: "AB"
示例 3:
輸入: 701 輸出: "ZY"
題解:
十進制轉化爲26進制,每次(num-1)%26便可獲得一個字符。
參考代碼:


1 class Solution { 2 public: 3 string convertToTitle(int n) { 4 string res = ""; 5 while(n > 0){ 6 int mod = (n-1) % 26; 7 res += ('A' + mod); 8 n = (n-1) / 26; 9 } 10 reverse(res.begin(), res.end()); 11 return res; 12 } 13 };
第三題 旋轉鏈表
給定一個鏈表,旋轉鏈表,將鏈表每一個節點向右移動 k 個位置,其中 k 是非負數。
示例 1:
輸入: 1->2->3->4->5->NULL, k = 2 輸出: 4->5->1->2->3->NULL 解釋: 向右旋轉 1 步: 5->1->2->3->4->NULL 向右旋轉 2 步: 4->5->1->2->3->NULL
示例 2:
輸入: 0->1->2->NULL, k = 4 輸出: 解釋: 向右旋轉 1 步: 2->0->1->NULL 向右旋轉 2 步: 1->2->0->NULL 向右旋轉 3 步: 向右旋轉 4 步: 2->0->1->NULL0->1->2->NULL2->0->1->NULL
題解:
先頭尾相連,而後再斷開。
參考代碼:


1 /** 2 * Definition for singly-linked list. 3 * struct ListNode { 4 * int val; 5 * ListNode *next; 6 * ListNode(int x) : val(x), next(NULL) {} 7 * }; 8 */ 9 class Solution { 10 public: 11 ListNode* rotateRight(ListNode* head, int k) 12 { 13 if(!head||k==0)return head; 14 15 ListNode *tail=head; 16 int size=1; 17 while(tail->next) 18 { 19 size++; 20 tail=tail->next; 21 } 22 if(k%size==0) return head; 23 24 tail->next=head; 25 int m=size-k%size; 26 while(m--) tail=tail->next; 27 ListNode *res=tail->next; 28 tail->next=nullptr; 29 return res; 30 } 31 };
第五次模擬
第一題 二叉樹的層平均值
給定一個非空二叉樹, 返回一個由每層節點平均值組成的數組.
示例 1:
輸入: 3 / \ 9 20 / \ 15 7 輸出: [3, 14.5, 11] 解釋: 第0層的平均值是 3, 第1層是 14.5, 第2層是 11. 所以返回 [3, 14.5, 11].
注意:
- 節點值的範圍在32位有符號整數範圍內。
題解:
用隊列存儲,每次取一層求平均值。
參考代碼:


1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 vector<double> averageOfLevels(TreeNode* root) { 13 vector<double> res; 14 queue<TreeNode*> que; 15 TreeNode* p,*last=root; 16 double sum=0; 17 int count=0; 18 que.push(root); 19 while(!que.empty()) 20 { 21 p=que.front(); 22 sum+=(double)p->val; 23 count++; 24 que.pop(); 25 if(p->left) que.push(p->left); 26 if(p->right) que.push(p->right); 27 if(p==last) 28 { 29 res.push_back(sum/(double)count); 30 sum=count=0; 31 last=que.back(); 32 } 33 } 34 return res; 35 } 36 };
第二題 同構字符串
給定兩個字符串 s 和 t,判斷它們是不是同構的。
若是 s 中的字符能夠被替換獲得 t ,那麼這兩個字符串是同構的。
全部出現的字符都必須用另外一個字符替換,同時保留字符的順序。兩個字符不能映射到同一個字符上,但字符能夠映射本身自己。
示例 1:
輸入: s = t = 輸出: true "egg","add"
示例 2:
輸入: s = t = 輸出: false"foo","bar"
示例 3:
輸入: s = t = 輸出: true"paper","title"
說明:
你能夠假設 s 和 t 具備相同的長度。
題解:
用兩個umordered_map記錄兩邊的對應關係便可。
參考代碼:


1 class Solution { 2 public: 3 bool isIsomorphic(string s, string t) 4 { 5 unordered_map<char,char> ump,ump2; 6 int len=s.length(); 7 if(len==0) return true; 8 9 for(int i=0;i<len;++i) 10 { 11 if(ump.count(s[i])) 12 { 13 if(ump[s[i]]!=t[i]) 14 return false; 15 continue; 16 } 17 if(ump2.count(t[i])) 18 { 19 if(ump2.count(t[i])!=s[i]) 20 return false; 21 continue; 22 } 23 ump[s[i]]=t[i]; 24 ump2[t[i]]=s[i]; 25 26 } 27 return true; 28 } 29 };
第三題 括號生成
給出 n 表明生成括號的對數,請你寫出一個函數,使其可以生成全部可能的而且有效的括號組合。
例如,給出 n = 3,生成結果爲:
[ "((()))", "(()())", "(())()", "()(())", "()()()" ]
題解:
遞歸生成,中間加一些判斷是否知足正確的括號匹配規則便可。
參考代碼:


1 class Solution { 2 private: 3 vector<string> ans; 4 public: 5 6 void dfs(string s,int l,int r,int n) 7 { 8 if(l==n && r==n) 9 { 10 ans.push_back(s); 11 return ; 12 } 13 if(l==r) dfs(s+'(',l+1,r,n); 14 else if(l>r && l<=n && r<=n) 15 { 16 if(l<n) dfs(s+'(',l+1,r,n),dfs(s+')',l,r+1,n); 17 else dfs(s+')',l,r+1,n); 18 } 19 } 20 21 vector<string> generateParenthesis(int n) 22 { 23 if(n==0) return ans; 24 dfs("",0,0,n); 25 return ans; 26 } 27 };
第六次模擬
第一題 最長字符串鏈
給出一個單詞列表,其中每一個單詞都由小寫英文字母組成。
若是咱們能夠在 word1
的任何地方添加一個字母使其變成 word2
,那麼咱們認爲 word1
是 word2
的前身。例如,"abc"
是 "abac"
的前身。
詞鏈是單詞 [word_1, word_2, ..., word_k]
組成的序列,k >= 1
,其中 word_1
是 word_2
的前身,word_2
是 word_3
的前身,依此類推。
從給定單詞列表 words
中選擇單詞組成詞鏈,返回詞鏈的最長可能長度。
示例:
輸入:["a","b","ba","bca","bda","bdca"] 輸出:4 解釋:最長單詞鏈之一爲 "a","ba","bda","bdca"。
提示:
1 <= words.length <= 1000
1 <= words[i].length <= 16
words[i]
僅由小寫英文字母組成。
題解:
先按長度排序,而後判斷是否知足包含關係,而後dp便可。
參考代碼:


1 class Solution { 2 3 // a是不是b的前身 4 bool isFor(string& a, string& b) { 5 if(b.size() - a.size() == 1) { 6 int i = 0, j = 0; 7 while(i < a.size() && j < b.size()) { 8 if(a[i] == b[j]) i++; 9 j++; 10 } 11 if(i == a.size()) return true; 12 } 13 return false; 14 } 15 16 public: 17 18 int longestStrChain(vector<string>& words) { 19 if(words.size() < 2) 20 return words.size(); 21 22 vector<int> dp(words.size(), 1); 23 int res = 1; 24 25 // 按字符串長度遞增排序 26 sort(words.begin(), words.end(), 27 [](string a, string b) {return a.size() < b.size();}); 28 29 for(int i = 0; i < words.size(); i++) { 30 for(int j = i - 1; j >= 0; j--) { 31 if(isFor(words[j], words[i])) { 32 dp[i] = max(dp[i], dp[j] + 1); 33 } 34 } 35 res = max(res, dp[i]); 36 } 37 38 return res; 39 } 40 };
第二題 分數到小數
給定兩個整數,分別表示分數的分子 numerator 和分母 denominator,以字符串形式返回小數。
若是小數部分爲循環小數,則將循環的部分括在括號內。
示例 1:
輸入: numerator = 1, denominator = 2 輸出: "0.5"
示例 2:
輸入: numerator = 2, denominator = 1 輸出: "2"
示例 3:
輸入: numerator = 2, denominator = 3 輸出: "0.(6)"
題解:
這裏有一個技巧,就是咱們能夠每次把被除數*10,而後去除以除數,若是出現了被除數重複的狀況,就是出現了循環節。
參考代碼:


1 class Solution { 2 public: 3 string fractionToDecimal(int numerator, int denominator) 4 { 5 if(numerator==INT_MIN&&denominator==-1)//邊界條件,無法直接除,由於除完結果溢出 6 return "2147483648"; 7 if(numerator==-1&&denominator==INT_MIN)//邊界條件,都是int類型,無法除 8 return "0.0000000004656612873077392578125"; 9 int shang=numerator/denominator,yushu=numerator%denominator;//記錄商和餘數 10 string res;//最終要返回的string 11 if(double(numerator)/double(denominator)<0)//若是兩個數一正一負 12 { 13 if(shang==0)//若是商爲0 14 res='-'+to_string(abs(shang));//可能有的同窗疑惑爲何要這樣處理,好比7/-12,除完shang爲0,可是咱們要的是-0 15 else 16 res=to_string(shang);//若是不爲0,那麼直接處理 17 } 18 else//若是都是正數或者都是負數 19 res=to_string(shang);//直接處理 20 if(yushu==0)//若是餘數爲0,那麼到此爲止,返回res就能夠了 21 return res; 22 res+='.';//若是還有餘數,那麼要加個小數點 23 unordered_map<int,int>record;//記錄出現過的餘數和餘數除以除數獲得的商的位置 24 while(yushu!=0) 25 { 26 yushu=abs(yushu);//餘數有多是負的,全都轉爲正數 27 denominator=abs(denominator);//除數也轉爲正數 28 yushu*=10;//餘數乘10,做爲新的被除數 29 if(record.count(yushu))//若是以前出現過了這個餘數,那麼能夠取出循環體了 30 { 31 int start=record[yushu],end=res.size()-1;//start和end表示循環體的開端和末尾 32 res=res.substr(0,start)+'('+res.substr(start,end-start+1)+')';//加一下括號 33 return res;//直接返回 34 } 35 record[yushu]=res.size();//若是沒出現過,那麼記錄在record中,value是這個餘數除以除數獲得的商應該放的位置 36 shang=yushu/denominator;//更新商 37 yushu=yushu%denominator;//更新餘數 38 res+=to_string(shang);//加入最新的商 39 } 40 return res;//若是一直沒有出現重複的餘數,那麼最終跳出循環後直接返回res 41 } 42 };
第三題 缺失的第一個正數(困難)
給定一個未排序的整數數組,找出其中沒有出現的最小的正整數。
示例 1:
輸入: [1,2,0] 輸出: 3
示例 2:
輸入: [3,4,-1,1] 輸出: 2
示例 3:
輸入: [7,8,9,11,12] 輸出: 1
說明:
你的算法的時間複雜度應爲O(n),而且只能使用常數級別的空間
題解:
咱們把對應的數字放在對應的位置,eg 1放在nums[0]這裏,最後去找第一個不對應的位置,即爲答案。
參考代碼:


1 class Solution { 2 public: 3 int firstMissingPositive(vector<int>& nums) 4 { 5 int n=nums.size(); 6 if(n==0) return 1; 7 int flag; 8 for(int i=0;i<n;++i) 9 { 10 if(nums[i]>=1&&nums[i]<=n && nums[i]!=(i+1)) 11 { 12 flag=nums[nums[i]-1]; 13 nums[nums[i]-1]=nums[i]; 14 while(flag>=1&&flag<=n && nums[flag-1]!=flag) 15 swap(flag,nums[flag-1]); 16 } 17 } 18 int ans=n+1; 19 for(int i=0;i<nums.size();++i) 20 { 21 if(nums[i]!=i+1) 22 { 23 ans=i+1; 24 break; 25 } 26 } 27 return ans; 28 } 29 };
第七次模擬
第一題 長度最小的子數組
給定一個含有 n 個正整數的數組和一個正整數 s ,找出該數組中知足其和 ≥ s 的長度最小的連續子數組。若是不存在符合條件的連續子數組,返回 0。
示例:
輸入: 輸出: 2 解釋: 子數組 是該條件下的長度最小的連續子數組。 s = 7, nums = [2,3,1,2,4,3][4,3]
進階:
若是你已經完成了O(n) 時間複雜度的解法, 請嘗試 O(n log n) 時間複雜度的解法。
題解:
雙指針作法。
參考代碼:


1 class Solution { 2 public: 3 int minSubArrayLen(int s, vector<int>& nums) 4 { 5 int n = nums.size(); 6 int ans = INT_MAX; 7 int left = 0; 8 int sum = 0; 9 for (int i = 0; i < n; i++) { 10 sum += nums[i]; 11 while (sum >= s) { 12 ans = min(ans, i + 1 - left); 13 sum -= nums[left++]; 14 } 15 } 16 return (ans != INT_MAX) ? ans : 0; 17 } 18 };
第二題 交換字符使得字符串相同
有兩個長度相同的字符串 s1
和 s2
,且它們其中 只含有 字符 "x"
和 "y"
,你須要經過「交換字符」的方式使這兩個字符串相同。
每次「交換字符」的時候,你均可以在兩個字符串中各選一個字符進行交換。
交換隻能發生在兩個不一樣的字符串之間,絕對不能發生在同一個字符串內部。也就是說,咱們能夠交換 s1[i]
和 s2[j]
,但不能交換 s1[i]
和 s1[j]
。
最後,請你返回使 s1
和 s2
相同的最小交換次數,若是沒有方法可以使得這兩個字符串相同,則返回 -1
。
示例 1:
輸入:s1 = "xx", s2 = "yy" 輸出:1 解釋: 交換 s1[0] 和 s2[1],獲得 s1 = "yx",s2 = "yx"。
示例 2:
輸入:s1 = "xy", s2 = "yx" 輸出:2 解釋: 交換 s1[0] 和 s2[0],獲得 s1 = "yy",s2 = "xx" 。 交換 s1[0] 和 s2[1],獲得 s1 = "xy",s2 = "xy" 。 注意,你不能交換 s1[0] 和 s1[1] 使得 s1 變成 "yx",由於咱們只能交換屬於兩個不一樣字符串的字符。
示例 3:
輸入:s1 = "xx", s2 = "xy" 輸出:-1
示例 4:
輸入:s1 = "xxyyxyxyxx", s2 = "xyyxyxxxyx" 輸出:4
提示:
1 <= s1.length, s2.length <= 1000
s1, s2
只包含'x'
或'y'
。
題解:
咱們能夠找出對應位置不一樣的,並記錄兩種不一樣的數量即:x : y和y : x的數量,而後對於x : y的,每兩個則須要一次交換,對於y : x也同樣,若是兩則的數量有剩餘的話,對於一個x : y和一個y : x則須要兩次交換才行。
參考代碼:


1 class Solution { 2 public: 3 int minimumSwap(string s1, string s2) 4 { 5 int n=s1.length(),m=s2.length(); 6 if(n==0) return 0; 7 int cnt1=0,cnt2=0,ans=0; 8 9 for(int i=0;i<n;++i) 10 { 11 if(s1[i]=='x'&&s2[i]=='y') cnt1++; 12 if(s1[i]=='y'&&s2[i]=='x') cnt2++; 13 } 14 ans=ans+cnt1/2+cnt2/2; 15 cnt1%=2;cnt2%=2; 16 ans=ans+cnt1*2; 17 if(cnt1!=cnt2) return -1; 18 else return ans; 19 } 20 };
第三題 二叉樹最大寬度
給定一個二叉樹,編寫一個函數來獲取這個樹的最大寬度。樹的寬度是全部層中的最大寬度。這個二叉樹與滿二叉樹(full binary tree)結構相同,但一些節點爲空。
每一層的寬度被定義爲兩個端點(該層最左和最右的非空節點,兩端點間的null
節點也計入長度)之間的長度。
示例 1:
輸入: 1 / \ 3 2 / \ \ 5 3 9 輸出: 4 解釋: 最大值出如今樹的第 3 層,寬度爲 4 (5,3,null,9)。
示例 2:
輸入: 1 / 3 / \ 5 3 輸出: 2 解釋: 最大值出如今樹的第 3 層,寬度爲 2 (5,3)。
示例 3:
輸入: 1 / \ 3 2 / 5 輸出: 2 解釋: 最大值出如今樹的第 2 層,寬度爲 2 (3,2)。
示例 4:
輸入: 1 / \ 3 2 / \ 5 9 / \ 6 7 輸出: 8 解釋: 最大值出如今樹的第 4 層,寬度爲 8 (6,null,null,null,null,null,null,7)。
注意: 答案在32位有符號整數的表示範圍內。
題解:
分層記錄便可。(不知道爲啥力扣的指針總是編譯錯誤。。。)
參考代碼:


1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 int widthOfBinaryTree(TreeNode* root) 13 { 14 if(!root) return 0; 15 queue<TreeNode*> Q; 16 Q.push(root); 17 int ans = 0; 18 while(Q.size()) 19 { 20 int cnt = Q.size(); 21 int f = -1; 22 int r = -1; 23 for(int i = 0;i < cnt;++i) 24 { 25 TreeNode* cur = Q.front();Q.pop(); 26 if(cur && f < 0) r = f=i; 27 if(cur) r=i; 28 if(!cur) 29 { 30 if(f > -1) 31 { 32 Q.push(NULL); 33 Q.push(NULL); 34 } 35 continue; 36 } 37 38 Q.push(cur->left); 39 Q.push(cur->right); 40 } 41 if(f > -1){ 42 ans = max(ans,r-f+1); 43 }else break; 44 45 } 46 return ans; 47 } 48 };
第八次模擬
第一題 課程表
如今你總共有 n 門課須要選,記爲 0
到 n-1
。
在選修某些課程以前須要一些先修課程。 例如,想要學習課程 0 ,你須要先完成課程 1 ,咱們用一個匹配來表示他們: [0,1]
給定課程總量以及它們的先決條件,判斷是否可能完成全部課程的學習?
示例 1:
輸入: 2, [[1,0]] 輸出: true 解釋: 總共有 2 門課程。學習課程 1 以前,你須要完成課程 0。因此這是可能的。
示例 2:
輸入: 2, [[1,0],[0,1]] 輸出: false 解釋: 總共有 2 門課程。學習課程 1 以前,你須要先完成課程 0;而且學習課程 0 以前,你還應先完成課程 1。這是不可能的。
說明:
- 輸入的先決條件是由邊緣列表表示的圖形,而不是鄰接矩陣。詳情請參見圖的表示法。
- 你能夠假定輸入的先決條件中沒有重複的邊。
提示:
- 這個問題至關於查找一個循環是否存在於有向圖中。若是存在循環,則不存在拓撲排序,所以不可能選取全部課程進行學習。
- 經過 DFS 進行拓撲排序 - 一個關於Coursera的精彩視頻教程(21分鐘),介紹拓撲排序的基本概念。
-
拓撲排序也能夠經過 BFS 完成。
題解:
拓撲排序板題。
參考代碼:


1 class Solution { 2 public: 3 bool canFinish(int n, vector<vector<int>>& p) 4 { 5 if(n==0) return true; 6 vector<int> w[n+1]; 7 int m=p.size(),cnt[n]={0}; 8 9 for(int i=0;i<m;++i) 10 { 11 w[p[i][0]].push_back(p[i][1]); 12 cnt[p[i][1]]++; 13 } 14 15 queue<int> q; 16 for(int i=0;i<n;++i) 17 if(cnt[i]==0) q.push(i); 18 19 while(!q.empty()) 20 { 21 int u=q.front();q.pop(); 22 for(int i=0;i<w[u].size();++i) 23 { 24 int v=w[u][i]; 25 --cnt[v]; 26 if(cnt[v]==0) q.push(v); 27 } 28 } 29 bool flag=true; 30 for(int i=0;i<n;++i) 31 if(cnt[i]) 32 { 33 flag=false; 34 break; 35 } 36 37 return flag; 38 } 39 };
第二題 循環碼排列
給你兩個整數 n
和 start
。你的任務是返回任意 (0,1,2,,...,2^n-1)
的排列 p
,而且知足:
p[0] = start
p[i]
和p[i+1]
的二進制表示形式只有一位不一樣p[0]
和p[2^n -1]
的二進制表示形式也只有一位不一樣
示例 1:
輸入:n = 2, start = 3 輸出:[3,2,0,1] 解釋:這個排列的二進制表示是 (11,10,00,01) 全部的相鄰元素都有一位是不一樣的,另外一個有效的排列是 [3,1,0,2]
示例 2:
輸出:n = 3, start = 2 輸出:[2,6,7,5,4,0,1,3] 解釋:這個排列的二進制表示是 (010,110,111,101,100,000,001,011)
提示:
1 <= n <= 16
0 <= start < 2^n
題解:
格雷碼。
參考代碼:


1 int gray[70000]; 2 class Solution { 3 public: 4 vector<int> circularPermutation(int n, int start) 5 { 6 vector<int> ans; 7 for (int i = 0; i < (1 << n); ++i) 8 gray[i] = (i ^ (i >> 1)); 9 int pos = 0; 10 for (int i = 0; i < (1 << n); ++i) 11 if (gray[i] == start) { 12 pos = i; 13 break; 14 } 15 for (int i = pos; i < (1 << n); ++i) 16 ans.push_back(gray[i]); 17 for (int i = 0; i < pos; ++i) 18 ans.push_back(gray[i]); 19 return ans; 20 } 21 };
第三題 和至少爲 K 的最短子數組
返回 A
的最短的非空連續子數組的長度,該子數組的和至少爲 K
。
若是沒有和至少爲 K
的非空子數組,返回 -1
。
示例 1:
輸入:A = [1], K = 1 輸出:1
示例 2:
輸入:A = [1,2], K = 4 輸出:-1
示例 3:
輸入:A = [2,-1,2], K = 3 輸出:3
提示:
1 <= A.length <= 50000
-10 ^ 5 <= A[i] <= 10 ^ 5
1 <= K <= 10 ^ 9
題解:
單調棧維護前綴和遞增。而後去二分查詢距離最近的知足條件的數所在位置。
參考代碼:


1 class Solution { 2 public: 3 int shortestSubarray(vector<int>& A, int K) { 4 if(A.size() == 0) 5 return -1; 6 int ans = A.size() + 1; 7 vector<vector<int>> s; //s中的每個元素都是一個長度爲2的數組{到地址爲止的count值,地址} 8 vector<int> leftBound = {0,-1}; 9 s.push_back(leftBound); 10 int count = 0; 11 for(int i = 0;i<A.size();i++) 12 { 13 if(A[i] >= K) 14 return 1; 15 //維護到i爲止的累加和count 16 count += A[i]; 17 //更新ans,須要用二分查找下降時間複雜度 18 int left = 0; 19 int right = s.size() - 1; 20 while(left < right) 21 { 22 int mid = (left + right) / 2 + 1; 23 if(count - s[mid][0] < K) 24 right = mid - 1; 25 else 26 left = mid; 27 } 28 if(count - s[left][0] >= K) 29 ans = min(ans,i-s[left][1]); 30 //維護單調遞增棧s 31 while(s.size() > 0 && s.back()[0] >= count) 32 s.pop_back(); 33 vector<int> temp = {count,i}; 34 s.push_back(temp); 35 } 36 return ans <= A.size() ? ans : -1;//檢查是否存在知足題意的子數組 37 } 38 };