模擬一
第一題 字符串中的單詞個數(簡單)
統計字符串中的單詞個數,這裏的單詞指的是連續的不是空格的字符。
請注意,你可以假定字符串裏不包括任何不可打印的字符。
示例:
輸入: "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 之外,這兩個數字都不會以零開頭。
進階:
如果輸入鏈表不能修改該如何處理?換句話說,你不能對列表中的節點進行翻轉。
示例:
輸入: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4) 輸出: 7 -> 8 -> 0 -> 7
題解:
將兩個鏈表反轉之後,按照位置加即可,設置一個進位add;
參考代碼:
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 };