模拟一
第一题 字符串中的单词个数(简单)
统计字符串中的单词个数,这里的单词指的是连续的不是空格的字符。
请注意,你可以假定字符串里不包括任何不可打印的字符。
示例:
输入: "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]==' ' && ii; 10 11 if(s[i]!=' ' && i<len) 12 { 13 while(s[i]!=' ' && i 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
- >。重置代码模板后可以看到这项改动。
题解:
使用优先队列(小顶堆),首先将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(vectorint>>& nums) { 23 priority_queue , 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){ 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) 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 vectorint>> tree; 4 vector<int> res, count; 5 6 vector<int> sumOfDistancesInTree(int N, 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 };