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


    第一次模拟

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

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

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

    示例:

    输入: "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 之外,这两个数字都不会以零开头。

    进阶:

    如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。

    示例:

    输入: (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 };
    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
    解释:
    从根到叶子节点路径 1->2 代表数字 12.
    从根到叶子节点路径 1->3 代表数字 13.
    因此,数字总和 = 12 + 13 = 25.

    示例 2:

    输入: [4,9,0,5,1]
        4
       / 
      9   0
     / 
    5   1
    输出: 1026
    解释:
    从根到叶子节点路径 4->9->5 代表数字 495.
    从根到叶子节点路径 4->9->1 代表数字 491.
    从根到叶子节点路径 4->0 代表数字 40.
    因此,数字总和 = 495 + 491 + 40 = 1026.

    题解: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
    输出: 2->0->1->NULL
    解释:
    向右旋转 1 步: 2->0->1->NULL
    向右旋转 2 步: 1->2->0->NULL
    向右旋转 3 步: 0->1->2->NULL
    向右旋转 4 步: 2->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 = "egg", t = "add"
    输出: true
    

    示例 2:

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

    示例 3:

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

    说明:
    你可以假设 和 具有相同的长度。

    题解:

    用两个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。

    示例: 

    输入: s = 7, nums = [2,3,1,2,4,3]
    输出: 2
    解释: 子数组 [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++
  • 相关阅读:
    【JVM】tomcat参数调整
    windows 资源监视器
    svn搭建相关
    mysqlli
    整理知识
    【刷题】洛谷 P4142 洞穴遇险
    【刷题】洛谷 P4143 采集矿石
    【刷题】BZOJ 4199 [Noi2015]品酒大会
    【刷题】BZOJ 2754 [SCOI2012]喵星球上的点名
    【刷题】BZOJ 3513 [MUTC2013]idiots
  • 原文地址:https://www.cnblogs.com/csushl/p/12295922.html
Copyright © 2020-2023  润新知