-
链表
-
树
-
数组
-
双指针
-
二分
-
-
贪心
-
动态规划
-
背包
-
其他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; }
-
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; }
-
原地置换
-
-
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; }
-
-
-
贪心
-
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; }
-
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; } };
-
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; } };
-
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; }
-
哈希
-
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; }