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

  • 链表

  • 数组

    •  双指针

    • 二分

  • 贪心

  • 动态规划

    • 背包

    • 其他DP

  • 队列

  • 搜索

数组

  • 双指针
    • NC247 最接近的三数之和
    • 思路:三数之和如果按照o(n^3)遍历肯定会爆,所以需要将复杂度降低到o(n^2),问题就来到了如何能完全枚举所有可能性结果呢;双指针(当value>target时,此时说明此处三数之和已经大于target,后面不需要进行遍历,故,先将nums进行排序之后进行双指针)
      int ClosestSum(vector<int>& nums, int target) {
          sort(nums.begin(), nums.end());
          int min_value = INT_MAX;
          int res = 0;
          for (int i = 0; i < nums.size() - 2; i++) {
              int left = i + 1, right = nums.size() - 1;
              while (left < right) {
                  int value = nums[i] + nums[left] + nums[right];
                  if (abs(value - target) < min_value) {
                      res = value;
                      min_value = abs(value - target);
                  }
                  //次处不需要接else: 上述最接近3数之和处不知道是大于target还是小于target,所以不能直接进行left++或者right--操作; [-10,20,10,40], target=20
                  if (value > target) {
                      right -= 1;
                  } else {
                      left += 1;
                  }
              }
          }
          return res;
      }
    • NC251 多数组第K小数
    • //思路:双指针,由于2个数组都是有序的,故只需要二分判断即可;
      int findKthNum(vector<int>& arr1, vector<int>& arr2, int target) {
          // write code here
          int arr1_left = 0, arr1_right = arr1.size() - 1;
          int arr2_left = 0, arr2_right = arr2.size() - 1;
          int arr1_idx = 0;
          int arr2_idx = 0;
          while (target != 1) {
              // 取出一半元素的idx索引(索引需要-1)
              int k = target / 2 - 1;
              // 索引位置不能超出数组的长度,故去min
              arr1_idx = min(arr1_left + k, arr1_right);
              arr2_idx = min(arr2_left + k, arr2_right);
              // 判断2个数组索引位置大小,如果小值的话,肯定不是需要的结果;
              if (arr1[arr1_idx] < arr2[arr2_idx]) {
                  target = target - (arr1_idx - arr1_left + 1);
                  arr1_left = arr1_idx + 1;
              } else {
                  target = target - (arr2_idx - arr2_left + 1);
                  arr2_left = arr2_idx + 1;
              }
              // 必须是大于,由于你上面target已经去掉了不可能答案,所以,剩下的数组一定满足答案;
              // 如果是==的话,由于你上面加1,导致你idx已经到最后一个位置,直接返回的话就有问题;
              if (arr1_left >  arr1_right) {
                  return arr2[arr2_left + target - 1];
              }
              if (arr2_left > arr2_right) {
                  return arr1[arr1_left + target - 1];
              }
          }
          return min(arr1[arr1_left], arr2[arr2_left]);
      }
    • NC286 调整数组顺序使奇数位于偶数的前面
    • vector<int> reOrderArrayTwo(vector<int>& array) {
          // write code here
          int left = 0, right = array.size() - 1;
          while (left < right) {
              while (left < right && array[left] % 2 == 1) {
                  left += 1;
              }
              while (left < right && array[right] % 2 == 0) {
                  right -= 1;
              }
              if (left < right) {
                  swap(array[left], array[right]);
                  left += 1;
                  right -= 1;
              }
          }
          return array;
      }
    • NC403 编辑距离为一

    • bool editdistance(string s, string t) {
          // write code here
          if (s.size() < t.size()) {
              swap(s, t);
          }
          if (s.size() - t.size() >= 2) {
              return false;
          }
      
          int i_left = 0, i_right = s.size() - 1;
          int j_left = 0, j_right = t.size() - 1;
          while (i_left < s.size() && j_left < t.size() && s[i_left] == t[j_left]) {
              i_left += 1, j_left += 1;
          }
      
          while (j_right > j_left && i_right > i_left && s[i_right] == t[j_right]) {
              j_right -= 1;
              i_right -= 1;
          }
      
          if (i_right - i_left == 0 || j_right - j_left == 0) {
              return true;
          }
          return false;
      }

  • 二分
    • NC254 合法的三角形个数
    • // 二分查找比现在大的数字的索引;由于是大于,所以nums[mid] ==  target的时候,也需要left++
      int find(vector<int>& nums, int target) {
          int left = 0, right = nums.size() - 1;
          while (left < right) {
              int mid = (left + right) / 2;
              if (nums[mid] <= target) {
                  left = mid + 1;
              } else {
                  right = mid;
              }
          }
          return left;
      }
      
      // 取出三角形两边进行寻找满足三角形最小的边,找到的idx和j之前的所有数字都满足条件
      int validTriangleNumber(vector<int>& nums) {
          sort(nums.begin(), nums.end());
          int res = 0;
          for (int i = nums.size() - 1; i >= 2; i--) {
              for (int j = i - 1; j >= 1; j--) {
                  int idx = find(nums, nums[i] - nums[j]);
                  if (j > idx) {
                      res += (j - idx);
                  }
              }
          }
          return res;
      }
  •  原地置换

    • NC256 数组中没有出现的数字

      • vector<int> findDisappearedNumbers(vector<int>& nums) {
            // write code here
            vector<int> res;
            for (int i = 0; i < nums.size(); i++) {
                //原地置换
                while (i + 1 != nums[i] && nums[nums[i] - 1] != nums[i]) {
                    swap(nums[i], nums[nums[i] - 1]);
                }
            }
            for (int i = 0; i < nums.size(); i++) {
                if (nums[i] != i + 1) {
                    res.push_back(i + 1);
                }
            }
            return res;
        }
  • 贪心

    • NC301 最大交换

    • string maximumSwap(string num) {
          // write code here
          unordered_map<char, int> un_mp;
          // 记录每个位置最后位置,最后位置是为了保证前面的小数被排到最后
          for (int i = 0; i < num.size(); i++) {
              un_mp[num[i]] = i;
          }
          for (int i = 0; i < num.size(); i++) {
              for (int j = 9; j >= 0; j--) {
                  char t = j + '0';
                  // 数字确实比较现在的值大,同时位置也偏后
                  if (un_mp[t] > i && t > num[i]) {
                      swap(num[i], num[un_mp[t]]);
                      return num;
                  }
              }
          }
          return num;
      }
  • 滑动窗口
    • NC407 区间子数组个数
    • // 区间个数不好求,转换为求l和r的结果,然后结果相减即可
      int countSubarray(vector<int>& nums, int l, int r) {
          // write code here
          int res_left = 0;
          int res_right = 0;
          int min_left_start = 0;
          int min_right_start = 0;
          for (int i = 0; i < nums.size(); i++) {
              if (nums[i] <= r) {
                  //由于区间之内都满足条件,所以满足子数组个数为本身长度(无序排列)
                  // [2,1,3] -> [2](2结尾) [1] [2,1](1结尾) [3] [1,3] [2,1,3](3结尾)
                  res_right += (i - min_right_start + 1);
              } else {
                  min_right_start = i + 1;
              }
      
              if (nums[i] < l) {
                  res_left += (i - min_left_start + 1);
              } else {
                  min_left_start = i + 1;
              }
          }
          return res_right - res_left;
      }
    • NC405 乘积小于K的子数组数量
    • // 乘积小于K的子数组,只需要确定子数组的left和right即可,典型的滑动窗口例子
      int subarrayCnt(vector<int>& nums, int k) {
          long sum = 1;
          int start = 0;
          int res = 0;
          for (int i = 0; i < nums.size(); i++) {
              sum = sum * nums[i];
              // start <= i, 防止除到下一个nums[i+1]元素
              while (sum >= k && start <= i) {
                  sum = sum / nums[start++];
              }
              res += (i - start + 1);
          }
          return res;
      }

  • NC 248 左叶子之和
  • 思路:左叶子节点,DFS和BFS都可以,BFS层次遍历即为模版,故不在写代码(只需要在倒数第二层判断即可);DFS(1.确定递归参数;2.确定终止条件;3.单层循环体)
    int res = 0;
    int sumOfLeftLeaves(TreeNode* root) {
        // write code here
        if (root == NULL) {
            return 0;
        }
        // 由于是累加和,故,不能return,需要用全局变量保存这个结果;
        if (root->left && root->left->left == NULL && root->left->right == NULL) {
            res += root->left->val;
        }
        // 上述res已经保存结果了,故每棵树返回结果可以忽略
        sumOfLeftLeaves(root->left);
        sumOfLeftLeaves(root->right);
        return res;
    }
  • NC372 插入二叉搜索树

  • class Solution {
    public:
        TreeNode* insertToBST(TreeNode* root, int val) {
            // write code here
            if (root == NULL) {
                return new TreeNode(val);
            }
            //如果root节点大于val的话,说明插入值只能在left;
            if (root->val > val) {
                if (root->left == NULL) {
                    TreeNode* temp = new TreeNode(val);
                    root->left = temp;
                } else {
                    root->left = insertToBST(root->left, val);
                }
            } else {
                //如果root节点小于val的话,说明插入值只能在right;
                if (root->right == NULL) {
                    TreeNode* temp = new TreeNode(val);
                    root->right = temp;
                } else {
                    root->right = insertToBST(root->right, val);
                }
            }
            return root;
        }
    };
  • NC297 删除二叉搜索树中的一个节点

  • class Solution {
    public:
        TreeNode* deleteNode(TreeNode* root, int key) {
            // write code here
            if (root == NULL) {
                return NULL;
            }
            if (root->val == key) {
                if (root->left == NULL && root->right) {
                    return root->right;
                }
                if (root->right == NULL && root->left) {
                    return root->left;
                }
                if (root->left == NULL && root->right == NULL) {
                    return NULL;
                }
                if (root->left && root->right) {
                    TreeNode* temp = root->right;
                    while (temp->left) {
                        temp = temp->left;
                    }
                    temp->left = root->left;
                    TreeNode* t = root;
                    root = root->right;
                    delete t;
                    return root;
                }
            }
    
            if (root->val > key) {
                root->left = deleteNode(root->left, key);
            }
            if (root->val < key) {
                root->right = deleteNode(root->right, key);
            }
            return root;
        }
    };
  • NC150 二叉树的个数

  • int numberOfTree(int n) {
        // write code here
        vector<long long> dp(n + 1, 0);
        // 个数等于=左个数 * 右个数;
        // 1的个数是1,左=1、右=0 ||左=0、右=1; 故dp[1] = 1; 
        dp[0] = 1;
        dp[1] = 1;
        for (int i = 2;i <= n; i++) {
            // 枚举左树个数
            // 根节点保持1个节点,故需要右树i-j-1
            for (int j = 0; j < i; j++) {
                // 递归公式:dp[i] = dp[i左] *  dp[i右]
                dp[i] += (dp[j] * dp[i - j - 1]) % 1000000007;
                dp[i] = dp[i] % 1000000007;
            }
        }
        return dp[n];
    }

字符串

  • 模拟
    • NC284 表示数值的字符串        
    • //可以解析为AEB; A->[+/-]C.D  CD都是整形数判断可以放到一起
      // A
      bool scanInt(string s, int& idx) {
          // +/-
          if (s[idx] == '+' || s[idx] == '-') {
              idx++;
          }
          return scanFloat(s, idx);
      }
      //C || D
      bool scanFloat(string s, int& idx) {
          int t = idx;
          while (idx < s.size() && s[idx] >= '0' && s[idx] <= '9') {
              idx++;
          }
          return idx > t;
      }
      bool isNumeric(string str) {
          // write code here
          if (str.size() == 0) {
              return false;
          }
          int i = 0;
          while (str[i] == ' ') {
              i += 1;
          }
              
          bool is_num = scanInt(str, i);
          if (str[i] == '.') {
              i++;
              is_num = scanFloat(str, i) || is_num;
          }
      
          if (str[i] == 'e' || str[i] == 'E') {
              i += 1;
              is_num = is_num && scanInt(str, i);
          }
          while (str[i] == ' ') {
              i += 1;
          }
              
          if (i == str.size() && is_num) {
              return true;
          }
          return false;
      }

  • 哈希

    • NC379 重排字符串

    • string rearrangestring(string str) {
          vector<int> v(27, 0);
          int max_num = 0;
          for (int i = 0; i < str.size(); i++) {
              v[str[i] - 'a'] += 1;
              max_num = max(max_num, v[str[i] - 'a']);
          }
          
          // 如果字符串超过一半以上的话,直接返回
          if (max_num > (str.size() + 1) / 2) {
              return "";
          }
              
          string res = "";
          int idx = 0;
          //先排偶数位置,再排奇数位置
          for (int j = 0; j < 26; j++) {
              while (v[j]) {
                  str[idx] = j + 'a';
                  idx = idx + 2;
                  v[j] -= 1;
                  if (idx >= str.size()) {
                      idx = 1;
                  }
              }
          }
          return str;
      }

搜索

  • dfs
    • NC285 矩阵中的路径
    • // DFS常规模版
      vector<vector<int> > dir = {{-1,0}, {1,0}, {0,1}, {0,-1}};
      bool res = 0;
      void dfs(vector<vector<char> > matrix, vector<vector<int> > visited, string word, int x, int y, int start) {
          if (start == word.size() - 1) {
              res = true;
              return;
          }
          for (int i = 0; i < 4; i++) {
              int newx = x + dir[i][0];
              int newy = y + dir[i][1];
              if (newx >= 0 && newx < matrix.size() 
                  && newy >= 0 && newy < matrix[0].size() 
                  && visited[newx][newy] == 0 
                  && matrix[newx][newy] == word[start + 1]) {
                      visited[newx][newy] = 1;
                      dfs(matrix, visited, word, newx, newy, start + 1);
                      visited[newx][newy] = 0;
              }
          }
      }
      bool hasPath(vector<vector<char> >& matrix, string word) {
          // write code here
          vector<vector<int> > visited(matrix.size(), vector<int>(matrix[0].size(), 0));
          for (int i = 0; i < matrix.size(); i++) {
              for (int j = 0; j < matrix[0].size(); j++) {
                  if (matrix[i][j] == word[0]) {
                      dfs(matrix, visited, word, i, j, 0);
                      if (res) {
                          return true;
                      }
                  }
              }
          }
          return false;
      }

  • BFS
    • NC249 拜访
    • 
      //BFS模板
      int countPath(vector<vector<int> >& CityMap, int n, int m) {
          // write code here
          vector<vector<int> > dir = {{-1,0}, {1, 0}, {0, 1}, {0, -1}};
          queue<pair<int,int> > q;
          for (int i = 0; i < n; i++) {
              for (int j = 0; j < m; j++) {
                  if (CityMap[i][j] == 1) {
                      q.push(make_pair(i, j));
                      break;
                  }
              }
          }
          int res = 0;
          while (res == 0 && !q.empty()) {
              int length = q.size();
              for (int i = 0; i < length; i++) {
                  int x = q.front().first;
                  int y = q.front().second;
                  q.pop();
                  for (int j = 0; j < 4; j++) {
                      int newx = dir[j][0] + x;
                      int newy = dir[j][1] + y;
                      if (newx >= 0 && newx < n && newy >= 0 && newy < m) {
                          if (CityMap[newx][newy] == 0) {
                              q.push(make_pair(newx, newy));
                          }
                          if (CityMap[newx][newy] == 2) {
                              res += 1;
                          }
                      }
                  }
              }
          }
          return res;
      }

模拟

  • NC291 数字序列中某一位的数字
  • 分析:https://blog.csdn.net/qq_33287871/article/details/107040649
    int findNthDigit(int n) {
        // write code here
        if (n < 10) {
            return n;
        }
        int num = 1; //数字的长度
        long long value = 9; //1位数:1-9(9个);2位数:10-99(90个); 3位数:100-999(900个)
        long long cur = 1; // 当前位数所表示最小值
        while (n >= value) {
            n -= value;
            num += 1;
            cur = cur * 10;
            value = cur * num * 9;
        }
    
        // 10-99,从0开始,故需要n-1
        long t = cur + (n - 1) / num;
        string temp = to_string(t);
        // 取出对应的位置;
        int tt =  temp[(t - 1) % num] - '0';
        return tt;
    }

  • NC375 去除重复字母
  • // 栈 + 贪心
    string removeDuplicateLetters(string str) {
        unordered_map<int, int> mp;
        vector<int> visited(26, 0);
        for (int i = 0; i < str.size(); i++) {
            mp[str[i] - 'a'] += 1;
        }
            
        string res = "";
        for (int i = 0; i < str.size(); i++) {
            if (visited[str[i] - 'a']) {
                mp[str[i] - 'a'] -= 1;
                continue;
            }
                
            while (res.size() && res.back() > str[i] && mp[res.back() - 'a'] > 0) {
                visited[res.back() - 'a'] = 0;
                res.pop_back();
            }
            res += str[i];
            mp[str[i] - 'a'] -= 1;
            visited[str[i] - 'a'] = 1;
        }
        return res;
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值