Advertisement

牛客网-刷题汇总(持续更新)

阅读量:

链表

数组

双指针

二分

贪心

动态规划

背包

其他DP

队列

搜索

数组

复制代码
              1. 思路:三数之和如果按照o(n^3)遍历肯定会爆,所以需要将复杂度降低到o(n^2),问题就来到了如何能完全枚举所有可能性结果呢;双指针(当value>target时,此时说明此处三数之和已经大于target,后面不需要进行遍历,故,先将nums进行排序之后进行双指针)

        
              2. int ClosestSum(vector<int>& nums, int target) {
        
              3.     sort(nums.begin(), nums.end());
        
              4.     int min_value = INT_MAX;
        
              5.     int res = 0;
        
              6.     for (int i = 0; i < nums.size() - 2; i++) {
        
              7.         int left = i + 1, right = nums.size() - 1;
        
              8.         while (left < right) {
        
              9.             int value = nums[i] + nums[left] + nums[right];
        
              10.             if (abs(value - target) < min_value) {
        
              11.                 res = value;
        
              12.                 min_value = abs(value - target);
        
              13.             }
        
              14.             //次处不需要接else: 上述最接近3数之和处不知道是大于target还是小于target,所以不能直接进行left++或者right--操作; [-10,20,10,40], target=20
        
              15.             if (value > target) {
        
              16.                 right -= 1;
        
              17.             } else {
        
              18.                 left += 1;
        
              19.             }
        
              20.         }
        
              21.     }
        
              22.     return res;
        
              23. }
复制代码
              1. //思路:双指针,由于2个数组都是有序的,故只需要二分判断即可;

        
              2. int findKthNum(vector<int>& arr1, vector<int>& arr2, int target) {
        
              3.     // write code here
        
              4.     int arr1_left = 0, arr1_right = arr1.size() - 1;
        
              5.     int arr2_left = 0, arr2_right = arr2.size() - 1;
        
              6.     int arr1_idx = 0;
        
              7.     int arr2_idx = 0;
        
              8.     while (target != 1) {
        
              9.         // 取出一半元素的idx索引(索引需要-1)
        
              10.         int k = target / 2 - 1;
        
              11.         // 索引位置不能超出数组的长度,故去min
        
              12.         arr1_idx = min(arr1_left + k, arr1_right);
        
              13.         arr2_idx = min(arr2_left + k, arr2_right);
        
              14.         // 判断2个数组索引位置大小,如果小值的话,肯定不是需要的结果;
        
              15.         if (arr1[arr1_idx] < arr2[arr2_idx]) {
        
              16.             target = target - (arr1_idx - arr1_left + 1);
        
              17.             arr1_left = arr1_idx + 1;
        
              18.         } else {
        
              19.             target = target - (arr2_idx - arr2_left + 1);
        
              20.             arr2_left = arr2_idx + 1;
        
              21.         }
        
              22.         // 必须是大于,由于你上面target已经去掉了不可能答案,所以,剩下的数组一定满足答案;
        
              23.         // 如果是==的话,由于你上面加1,导致你idx已经到最后一个位置,直接返回的话就有问题;
        
              24.         if (arr1_left >  arr1_right) {
        
              25.             return arr2[arr2_left + target - 1];
        
              26.         }
        
              27.         if (arr2_left > arr2_right) {
        
              28.             return arr1[arr1_left + target - 1];
        
              29.         }
        
              30.     }
        
              31.     return min(arr1[arr1_left], arr2[arr2_left]);
        
              32. }
复制代码
              1. vector<int> reOrderArrayTwo(vector<int>& array) {

        
              2.     // write code here
        
              3.     int left = 0, right = array.size() - 1;
        
              4.     while (left < right) {
        
              5.         while (left < right && array[left] % 2 == 1) {
        
              6.             left += 1;
        
              7.         }
        
              8.         while (left < right && array[right] % 2 == 0) {
        
              9.             right -= 1;
        
              10.         }
        
              11.         if (left < right) {
        
              12.             swap(array[left], array[right]);
        
              13.             left += 1;
        
              14.             right -= 1;
        
              15.         }
        
              16.     }
        
              17.     return array;
        
              18. }

NC403 编辑距离为一

复制代码
              1. bool editdistance(string s, string t) {

        
              2.     // write code here
        
              3.     if (s.size() < t.size()) {
        
              4.         swap(s, t);
        
              5.     }
        
              6.     if (s.size() - t.size() >= 2) {
        
              7.         return false;
        
              8.     }
        
              9.  
        
              10.     int i_left = 0, i_right = s.size() - 1;
        
              11.     int j_left = 0, j_right = t.size() - 1;
        
              12.     while (i_left < s.size() && j_left < t.size() && s[i_left] == t[j_left]) {
        
              13.         i_left += 1, j_left += 1;
        
              14.     }
        
              15.  
        
              16.     while (j_right > j_left && i_right > i_left && s[i_right] == t[j_right]) {
        
              17.         j_right -= 1;
        
              18.         i_right -= 1;
        
              19.     }
        
              20.  
        
              21.     if (i_right - i_left == 0 || j_right - j_left == 0) {
        
              22.         return true;
        
              23.     }
        
              24.     return false;
        
              25. }
复制代码
              1. // 二分查找比现在大的数字的索引;由于是大于,所以nums[mid] ==  target的时候,也需要left++

        
              2. int find(vector<int>& nums, int target) {
        
              3.     int left = 0, right = nums.size() - 1;
        
              4.     while (left < right) {
        
              5.         int mid = (left + right) / 2;
        
              6.         if (nums[mid] <= target) {
        
              7.             left = mid + 1;
        
              8.         } else {
        
              9.             right = mid;
        
              10.         }
        
              11.     }
        
              12.     return left;
        
              13. }
        
              14.  
        
              15. // 取出三角形两边进行寻找满足三角形最小的边,找到的idx和j之前的所有数字都满足条件
        
              16. int validTriangleNumber(vector<int>& nums) {
        
              17.     sort(nums.begin(), nums.end());
        
              18.     int res = 0;
        
              19.     for (int i = nums.size() - 1; i >= 2; i--) {
        
              20.         for (int j = i - 1; j >= 1; j--) {
        
              21.             int idx = find(nums, nums[i] - nums[j]);
        
              22.             if (j > idx) {
        
              23.                 res += (j - idx);
        
              24.             }
        
              25.         }
        
              26.     }
        
              27.     return res;
        
              28. }

原地置换

NC256 数组中没有出现的数字

复制代码
                    1. vector<int> findDisappearedNumbers(vector<int>& nums) {

            
                    2.     // write code here
            
                    3.     vector<int> res;
            
                    4.     for (int i = 0; i < nums.size(); i++) {
            
                    5.         //原地置换
            
                    6.         while (i + 1 != nums[i] && nums[nums[i] - 1] != nums[i]) {
            
                    7.             swap(nums[i], nums[nums[i] - 1]);
            
                    8.         }
            
                    9.     }
            
                    10.     for (int i = 0; i < nums.size(); i++) {
            
                    11.         if (nums[i] != i + 1) {
            
                    12.             res.push_back(i + 1);
            
                    13.         }
            
                    14.     }
            
                    15.     return res;
            
                    16. }

贪心

NC301 最大交换

复制代码
              1. string maximumSwap(string num) {

        
              2.     // write code here
        
              3.     unordered_map<char, int> un_mp;
        
              4.     // 记录每个位置最后位置,最后位置是为了保证前面的小数被排到最后
        
              5.     for (int i = 0; i < num.size(); i++) {
        
              6.         un_mp[num[i]] = i;
        
              7.     }
        
              8.     for (int i = 0; i < num.size(); i++) {
        
              9.         for (int j = 9; j >= 0; j--) {
        
              10.             char t = j + '0';
        
              11.             // 数字确实比较现在的值大,同时位置也偏后
        
              12.             if (un_mp[t] > i && t > num[i]) {
        
              13.                 swap(num[i], num[un_mp[t]]);
        
              14.                 return num;
        
              15.             }
        
              16.         }
        
              17.     }
        
              18.     return num;
        
              19. }
复制代码
              1. // 区间个数不好求,转换为求l和r的结果,然后结果相减即可

        
              2. int countSubarray(vector<int>& nums, int l, int r) {
        
              3.     // write code here
        
              4.     int res_left = 0;
        
              5.     int res_right = 0;
        
              6.     int min_left_start = 0;
        
              7.     int min_right_start = 0;
        
              8.     for (int i = 0; i < nums.size(); i++) {
        
              9.         if (nums[i] <= r) {
        
              10.             //由于区间之内都满足条件,所以满足子数组个数为本身长度(无序排列)
        
              11.             // [2,1,3] -> [2](2结尾) [1] [2,1](1结尾) [3] [1,3] [2,1,3](3结尾)
        
              12.             res_right += (i - min_right_start + 1);
        
              13.         } else {
        
              14.             min_right_start = i + 1;
        
              15.         }
        
              16.  
        
              17.         if (nums[i] < l) {
        
              18.             res_left += (i - min_left_start + 1);
        
              19.         } else {
        
              20.             min_left_start = i + 1;
        
              21.         }
        
              22.     }
        
              23.     return res_right - res_left;
        
              24. }
复制代码
              1. // 乘积小于K的子数组,只需要确定子数组的left和right即可,典型的滑动窗口例子

        
              2. int subarrayCnt(vector<int>& nums, int k) {
        
              3.     long sum = 1;
        
              4.     int start = 0;
        
              5.     int res = 0;
        
              6.     for (int i = 0; i < nums.size(); i++) {
        
              7.         sum = sum * nums[i];
        
              8.         // start <= i, 防止除到下一个nums[i+1]元素
        
              9.         while (sum >= k && start <= i) {
        
              10.             sum = sum / nums[start++];
        
              11.         }
        
              12.         res += (i - start + 1);
        
              13.     }
        
              14.     return res;
        
              15. }

复制代码
        1. 思路:左叶子节点,DFS和BFS都可以,BFS层次遍历即为模版,故不在写代码(只需要在倒数第二层判断即可);DFS(1.确定递归参数;2.确定终止条件;3.单层循环体)

    
        2. int res = 0;
    
        3. int sumOfLeftLeaves(TreeNode* root) {
    
        4.     // write code here
    
        5.     if (root == NULL) {
    
        6.         return 0;
    
        7.     }
    
        8.     // 由于是累加和,故,不能return,需要用全局变量保存这个结果;
    
        9.     if (root->left && root->left->left == NULL && root->left->right == NULL) {
    
        10.         res += root->left->val;
    
        11.     }
    
        12.     // 上述res已经保存结果了,故每棵树返回结果可以忽略
    
        13.     sumOfLeftLeaves(root->left);
    
        14.     sumOfLeftLeaves(root->right);
    
        15.     return res;
    
        16. }

NC372 插入二叉搜索树

复制代码
        1. class Solution {

    
        2. public:
    
        3.     TreeNode* insertToBST(TreeNode* root, int val) {
    
        4.         // write code here
    
        5.         if (root == NULL) {
    
        6.             return new TreeNode(val);
    
        7.         }
    
        8.         //如果root节点大于val的话,说明插入值只能在left;
    
        9.         if (root->val > val) {
    
        10.             if (root->left == NULL) {
    
        11.                 TreeNode* temp = new TreeNode(val);
    
        12.                 root->left = temp;
    
        13.             } else {
    
        14.                 root->left = insertToBST(root->left, val);
    
        15.             }
    
        16.         } else {
    
        17.             //如果root节点小于val的话,说明插入值只能在right;
    
        18.             if (root->right == NULL) {
    
        19.                 TreeNode* temp = new TreeNode(val);
    
        20.                 root->right = temp;
    
        21.             } else {
    
        22.                 root->right = insertToBST(root->right, val);
    
        23.             }
    
        24.         }
    
        25.         return root;
    
        26.     }
    
        27. };

NC297 删除二叉搜索树中的一个节点

复制代码
        1. class Solution {

    
        2. public:
    
        3.     TreeNode* deleteNode(TreeNode* root, int key) {
    
        4.         // write code here
    
        5.         if (root == NULL) {
    
        6.             return NULL;
    
        7.         }
    
        8.         if (root->val == key) {
    
        9.             if (root->left == NULL && root->right) {
    
        10.                 return root->right;
    
        11.             }
    
        12.             if (root->right == NULL && root->left) {
    
        13.                 return root->left;
    
        14.             }
    
        15.             if (root->left == NULL && root->right == NULL) {
    
        16.                 return NULL;
    
        17.             }
    
        18.             if (root->left && root->right) {
    
        19.                 TreeNode* temp = root->right;
    
        20.                 while (temp->left) {
    
        21.                     temp = temp->left;
    
        22.                 }
    
        23.                 temp->left = root->left;
    
        24.                 TreeNode* t = root;
    
        25.                 root = root->right;
    
        26.                 delete t;
    
        27.                 return root;
    
        28.             }
    
        29.         }
    
        30.  
    
        31.         if (root->val > key) {
    
        32.             root->left = deleteNode(root->left, key);
    
        33.         }
    
        34.         if (root->val < key) {
    
        35.             root->right = deleteNode(root->right, key);
    
        36.         }
    
        37.         return root;
    
        38.     }
    
        39. };

NC150 二叉树的个数

复制代码
        1. int numberOfTree(int n) {

    
        2.     // write code here
    
        3.     vector<long long> dp(n + 1, 0);
    
        4.     // 个数等于=左个数 * 右个数;
    
        5.     // 1的个数是1,左=1、右=0 ||左=0、右=1; 故dp[1] = 1; 
    
        6.     dp[0] = 1;
    
        7.     dp[1] = 1;
    
        8.     for (int i = 2;i <= n; i++) {
    
        9.         // 枚举左树个数
    
        10.         // 根节点保持1个节点,故需要右树i-j-1
    
        11.         for (int j = 0; j < i; j++) {
    
        12.             // 递归公式:dp[i] = dp[i左] *  dp[i右]
    
        13.             dp[i] += (dp[j] * dp[i - j - 1]) % 1000000007;
    
        14.             dp[i] = dp[i] % 1000000007;
    
        15.         }
    
        16.     }
    
        17.     return dp[n];
    
        18. }

字符串

复制代码
              1. //可以解析为AEB; A->[+/-]C.D  CD都是整形数判断可以放到一起

        
              2. // A
        
              3. bool scanInt(string s, int& idx) {
        
              4.     // +/-
        
              5.     if (s[idx] == '+' || s[idx] == '-') {
        
              6.         idx++;
        
              7.     }
        
              8.     return scanFloat(s, idx);
        
              9. }
        
              10. //C || D
        
              11. bool scanFloat(string s, int& idx) {
        
              12.     int t = idx;
        
              13.     while (idx < s.size() && s[idx] >= '0' && s[idx] <= '9') {
        
              14.         idx++;
        
              15.     }
        
              16.     return idx > t;
        
              17. }
        
              18. bool isNumeric(string str) {
        
              19.     // write code here
        
              20.     if (str.size() == 0) {
        
              21.         return false;
        
              22.     }
        
              23.     int i = 0;
        
              24.     while (str[i] == ' ') {
        
              25.         i += 1;
        
              26.     }
        
              27.         
        
              28.     bool is_num = scanInt(str, i);
        
              29.     if (str[i] == '.') {
        
              30.         i++;
        
              31.         is_num = scanFloat(str, i) || is_num;
        
              32.     }
        
              33.  
        
              34.     if (str[i] == 'e' || str[i] == 'E') {
        
              35.         i += 1;
        
              36.         is_num = is_num && scanInt(str, i);
        
              37.     }
        
              38.     while (str[i] == ' ') {
        
              39.         i += 1;
        
              40.     }
        
              41.         
        
              42.     if (i == str.size() && is_num) {
        
              43.         return true;
        
              44.     }
        
              45.     return false;
        
              46. }

哈希

NC379 重排字符串

复制代码
              1. string rearrangestring(string str) {

        
              2.     vector<int> v(27, 0);
        
              3.     int max_num = 0;
        
              4.     for (int i = 0; i < str.size(); i++) {
        
              5.         v[str[i] - 'a'] += 1;
        
              6.         max_num = max(max_num, v[str[i] - 'a']);
        
              7.     }
        
              8.     
        
              9.     // 如果字符串超过一半以上的话,直接返回
        
              10.     if (max_num > (str.size() + 1) / 2) {
        
              11.         return "";
        
              12.     }
        
              13.         
        
              14.     string res = "";
        
              15.     int idx = 0;
        
              16.     //先排偶数位置,再排奇数位置
        
              17.     for (int j = 0; j < 26; j++) {
        
              18.         while (v[j]) {
        
              19.             str[idx] = j + 'a';
        
              20.             idx = idx + 2;
        
              21.             v[j] -= 1;
        
              22.             if (idx >= str.size()) {
        
              23.                 idx = 1;
        
              24.             }
        
              25.         }
        
              26.     }
        
              27.     return str;
        
              28. }

搜索

复制代码
              1. // DFS常规模版

        
              2. vector<vector<int> > dir = {{-1,0}, {1,0}, {0,1}, {0,-1}};
        
              3. bool res = 0;
        
              4. void dfs(vector<vector<char> > matrix, vector<vector<int> > visited, string word, int x, int y, int start) {
        
              5.     if (start == word.size() - 1) {
        
              6.         res = true;
        
              7.         return;
        
              8.     }
        
              9.     for (int i = 0; i < 4; i++) {
        
              10.         int newx = x + dir[i][0];
        
              11.         int newy = y + dir[i][1];
        
              12.         if (newx >= 0 && newx < matrix.size() 
        
              13.             && newy >= 0 && newy < matrix[0].size() 
        
              14.             && visited[newx][newy] == 0 
        
              15.             && matrix[newx][newy] == word[start + 1]) {
        
              16.                 visited[newx][newy] = 1;
        
              17.                 dfs(matrix, visited, word, newx, newy, start + 1);
        
              18.                 visited[newx][newy] = 0;
        
              19.         }
        
              20.     }
        
              21. }
        
              22. bool hasPath(vector<vector<char> >& matrix, string word) {
        
              23.     // write code here
        
              24.     vector<vector<int> > visited(matrix.size(), vector<int>(matrix[0].size(), 0));
        
              25.     for (int i = 0; i < matrix.size(); i++) {
        
              26.         for (int j = 0; j < matrix[0].size(); j++) {
        
              27.             if (matrix[i][j] == word[0]) {
        
              28.                 dfs(matrix, visited, word, i, j, 0);
        
              29.                 if (res) {
        
              30.                     return true;
        
              31.                 }
        
              32.             }
        
              33.         }
        
              34.     }
        
              35.     return false;
        
              36. }
复制代码
              1.  
        
              2. //BFS模板
        
              3. int countPath(vector<vector<int> >& CityMap, int n, int m) {
        
              4.     // write code here
        
              5.     vector<vector<int> > dir = {{-1,0}, {1, 0}, {0, 1}, {0, -1}};
        
              6.     queue<pair<int,int> > q;
        
              7.     for (int i = 0; i < n; i++) {
        
              8.         for (int j = 0; j < m; j++) {
        
              9.             if (CityMap[i][j] == 1) {
        
              10.                 q.push(make_pair(i, j));
        
              11.                 break;
        
              12.             }
        
              13.         }
        
              14.     }
        
              15.     int res = 0;
        
              16.     while (res == 0 && !q.empty()) {
        
              17.         int length = q.size();
        
              18.         for (int i = 0; i < length; i++) {
        
              19.             int x = q.front().first;
        
              20.             int y = q.front().second;
        
              21.             q.pop();
        
              22.             for (int j = 0; j < 4; j++) {
        
              23.                 int newx = dir[j][0] + x;
        
              24.                 int newy = dir[j][1] + y;
        
              25.                 if (newx >= 0 && newx < n && newy >= 0 && newy < m) {
        
              26.                     if (CityMap[newx][newy] == 0) {
        
              27.                         q.push(make_pair(newx, newy));
        
              28.                     }
        
              29.                     if (CityMap[newx][newy] == 2) {
        
              30.                         res += 1;
        
              31.                     }
        
              32.                 }
        
              33.             }
        
              34.         }
        
              35.     }
        
              36.     return res;
        
              37. }

模拟

复制代码
        1. 分析:

    
        2. int findNthDigit(int n) {
    
        3.     // write code here
    
        4.     if (n < 10) {
    
        5.         return n;
    
        6.     }
    
        7.     int num = 1; //数字的长度
    
        8.     long long value = 9; //1位数:1-9(9个);2位数:10-99(90个); 3位数:100-999(900个)
    
        9.     long long cur = 1; // 当前位数所表示最小值
    
        10.     while (n >= value) {
    
        11.         n -= value;
    
        12.         num += 1;
    
        13.         cur = cur * 10;
    
        14.         value = cur * num * 9;
    
        15.     }
    
        16.  
    
        17.     // 10-99,从0开始,故需要n-1
    
        18.     long t = cur + (n - 1) / num;
    
        19.     string temp = to_string(t);
    
        20.     // 取出对应的位置;
    
        21.     int tt =  temp[(t - 1) % num] - '0';
    
        22.     return tt;
    
        23. }

复制代码
        1. // 栈 + 贪心

    
        2. string removeDuplicateLetters(string str) {
    
        3.     unordered_map<int, int> mp;
    
        4.     vector<int> visited(26, 0);
    
        5.     for (int i = 0; i < str.size(); i++) {
    
        6.         mp[str[i] - 'a'] += 1;
    
        7.     }
    
        8.         
    
        9.     string res = "";
    
        10.     for (int i = 0; i < str.size(); i++) {
    
        11.         if (visited[str[i] - 'a']) {
    
        12.             mp[str[i] - 'a'] -= 1;
    
        13.             continue;
    
        14.         }
    
        15.             
    
        16.         while (res.size() && res.back() > str[i] && mp[res.back() - 'a'] > 0) {
    
        17.             visited[res.back() - 'a'] = 0;
    
        18.             res.pop_back();
    
        19.         }
    
        20.         res += str[i];
    
        21.         mp[str[i] - 'a'] -= 1;
    
        22.         visited[str[i] - 'a'] = 1;
    
        23.     }
    
        24.     return res;
    
        25. }

全部评论 (0)

还没有任何评论哟~