leetcode 字节跳动模拟面试编程题(持续更新~)

第一次模拟

第一题  字符串中的单词个数(简单)

统计字符串中的单词个数,这里的单词指的是连续的不是空格的字符。css

请注意,你能够假定字符串里不包括任何不可打印的字符。node

示例:算法

输入: "Hello, my name is John"
输出: 5
 
 题解:注意开头的空格。而后就一直while判断就好了,看看有多少个被空格间隔的单词。
 
参考代码:
 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 };
C++
 

第二题 两数相加 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 };
C++

 

第三题 最小区间(困难)

你有 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. 给定的列表可能包含重复元素,因此在这里升序表示 >= 。
  2. 1 <= k <= 3500
  3. -105 <= 元素的值 <= 105
  4. 对于使用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 };
C++

 

第二次模拟

第一题 重复的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 };
C++

 

第二题 分割数组的最大值(困难)

给定一个非负整数数组和一个整数 m,你须要将这个数组分红 个非空的连续子数组。设计一个算法使得这 个子数组各自和的最大值最小。

注意:
数组长度 知足如下条件:

  • 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 };
C++

 

第三题 树中距离之和(困难)

给定一个无向、连通的树。树中有 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 };
C++

 

 第三次模拟

 第一题 最大连续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. 1 <= A.length <= 20000
  2. 0 <= K <= A.length
  3. 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 };
C++

 

第二题 岛屿的最大面积

给定一个包含了一些 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 };
C++

第三题 求根到叶子节点数字之和

给定一个二叉树,它的每一个结点都存放一个 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 };
C++

第四次模拟

第一题 用户分组

有 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 };
C++

第二题 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 };
C++

第三题 旋转链表

 

给定一个链表,旋转链表,将链表每一个节点向右移动 个位置,其中 是非负数。

示例 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 };
C++

 

第五次模拟

第一题 二叉树的层平均值

给定一个非空二叉树, 返回一个由每层节点平均值组成的数组.

示例 1:

输入:
    3
   / \
  9  20
    /  \
   15   7
输出: [3, 14.5, 11]
解释:
第0层的平均值是 3,  第1层是 14.5, 第2层是 11. 所以返回 [3, 14.5, 11].

注意:

  1. 节点值的范围在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 };
C++

第二题  同构字符串

 

给定两个字符串 和 t,判断它们是不是同构的。

若是 中的字符能够被替换获得 ,那么这两个字符串是同构的。

全部出现的字符都必须用另外一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符能够映射本身自己。

示例 1:

输入: s = t = 
输出: true
"egg","add"

示例 2:

输入: s = t = 
输出: false"foo","bar"

示例 3:

输入: s = t = 
输出: true"paper","title"

说明:
你能够假设 和 具备相同的长度。

 

题解:

用两个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 };
C++

 

第三题  括号生成

 

给出 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 };
C++

第六次模拟

第一题 最长字符串链

 

给出一个单词列表,其中每一个单词都由小写英文字母组成。

若是咱们能够在 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. 1 <= words.length <= 1000
  2. 1 <= words[i].length <= 16
  3. 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 };
C++

 

第二题 分数到小数

 

给定两个整数,分别表示分数的分子 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 };
C++

 

第三题  缺失的第一个正数(困难)

 

给定一个未排序的整数数组,找出其中没有出现的最小的正整数。

示例 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 };
C++

 

第七次模拟

第一题 长度最小的子数组

 

给定一个含有 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 };
C++

 

第二题 交换字符使得字符串相同

有两个长度相同的字符串 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 };
C++

 

第三题 二叉树最大宽度

给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是全部层中的最大宽度。这个二叉树与满二叉树(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 };
C++

 

第八次模拟

第一题 课程表

如今你总共有 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。这是不可能的。

说明:

  1. 输入的先决条件是由边缘列表表示的图形,而不是邻接矩阵。详情请参见图的表示法
  2. 你能够假定输入的先决条件中没有重复的边。

提示:

  1. 这个问题至关于查找一个循环是否存在于有向图中。若是存在循环,则不存在拓扑排序,所以不可能选取全部课程进行学习。
  2. 经过 DFS 进行拓扑排序 - 一个关于Coursera的精彩视频教程(21分钟),介绍拓扑排序的基本概念。
  3. 拓扑排序也能够经过 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 };
C++

 

 

第二题 循环码排列

给你两个整数 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 };
C++

 

 

第三题 和至少为 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. 1 <= A.length <= 50000
  2. -10 ^ 5 <= A[i] <= 10 ^ 5
  3. 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 };
C++
相关文章
相关标签/搜索