1.哈希表:
哈希表是根据关键码的值而直接进行访问的数据结构
解决问题:一般哈希表都是用来快速判断一个元素是否出现集合里
常见的三种哈希结构
- 数组
- set(集合)
- map(映射)
力扣 242.有效的字母异位词
定义一个数组a记录字符串s里字符出现的次数。把字符映射到数组,再遍历 字符串s的时候,将 s[i] - ‘a’ 所在的元素做++ 操作,统计字符串s中字符出现的次数。检查字符串t中是否出现了这些字符,遍历字符串t,对t中出现的字符映射哈希表索引上的数值再做-1的操作。
class Solution {
public:
bool isAnagram(string s, string t) {
vector<int>a(26,0);
for(char i:s){
a[i-'a']++;
}
for(char i:t){
a[i-'a']--;
}
for(int i=0;i<a.size();i++){
if(a[i]) return false;
}
return true;
}
};
力扣 349. 两个数组的交集
这题用到unordered_set,unordered_set输出结果中的每个元素一定是唯一的,也就是说输出的结果的去重的, 同时可以不考虑输出结果的顺序
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int>result;
unordered_set<int>set(nums1.begin(),nums1.end());
for(int i:nums2){
if(set.find(i)!=set.end())
result.insert(i);
}
return vector<int>(result.begin(),result.end());
}
};
力扣 第202题. 快乐数
题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现,所以这道题目使用哈希法,来判断这个sum是否重复出现
class Solution {
public:
int hh(int n) {
int sum = 0;
while (n) {
sum += (n%10) * (n%10);
n /= 10;
}
return sum;
}
bool isHappy(int n) {set <int> t;
while(1){
int a;
a = hh(n);
if (a == 1) return true;
if (t.find(a) != t.end()) return false;
else t.insert(a);
n = a;
}
}
};
力扣 1. 两数之和
本题需要一个map来存放我们遍历过的元素,然后在遍历数组的时候去询问这个map,某元素是否出现在这个集合。数组中的元素作为key,value用来存下标。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
std::unordered_map <int,int> map;
for(int i = 0; i < nums.size(); i++) {
auto iter = map.find(target - nums[i]);
if(iter != map.end()) {
return {iter->second, i};
}
map.insert(pair<int, int>(nums[i], i));
}
return {};
}
};
力扣 383. 赎金信
本题用空间换取时间的哈希策略,用一个长度为26的数组来记录magazine里字母出现的次数。然后再用ransomNote去验证这个数组是否包含了ransomNote所需要的所有字母。
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int h[26] = {0};
if (ransomNote.size() > magazine.size())
return false;
for (int i = 0;i < magazine.size();i++){
h[magazine[i]-'a']++;
}
for (int i = 0;i < ransomNote.size();i++){
h[ransomNote[i]-'a']--;
if(h[ransomNote[i]-'a'] < 0)
return false;
}
return true;
}
};
2.字符串
力扣 541. 反转字符串II
在遍历字符串的过程中,只要让 i += (2 * k),i 每次移动 2 * k ,然后判断是否需要有反转的区间。
class Solution {
public:
string reverseStr(string s, int k) {
for (int i = 0; i < s.size();i += 2*k) {
if (i + k <= s.size() ) {
reverse (s.begin()+i, s.begin()+i+k);
}
else {
reverse (s.begin()+i, s.end());
}
}
return s;
}
};
替换数字
首先扩充数组到每个数字字符替换成 "number" 之后的大小,然后从后向前替换数字字符
#include <bits/stdc++.h>
using namespace std;
int main() {
string s;
while (cin >> s) {
int count = 0;
int sOldSize = s.size();
for (int i = 0; i < s.size(); i++) {
if (s[i] >= '0' && s[i] <= '9') {
count++;
}
}
s.resize(s.size() + count * 5);
int sNewSize = s.size();
for (int i = sNewSize - 1, j = sOldSize - 1; j < i; i--, j--) {
if (s[j] > '9' || s[j] < '0') {
s[i] = s[j];
} else {
s[i] = 'r';s[i - 1] = 'e';s[i - 2] = 'b';s[i - 3] = 'm'; s[i - 4] = 'u';
s[i - 5] = 'n';
i -= 5;
}
}
cout << s << endl;
}
}
力扣 151.翻转字符串里的单词
先移除多余空格,再将整个字符串反转,最后将每个单词反转
class Solution {
public:
void sc(string& s){
int sl=0;
for(int i=0;i<s.size();i++){
if(s[i]!=' '){
if(sl!=0) s[sl++]=' ';
while(i<s.size()&&s[i]!=' '){
s[sl++]=s[i++];
}
}
}
s.resize(sl);
}
string reverseWords(string s) {
sc(s);
reverse(s.begin(),s.end());
int a=0;
for(int i=0;i<=s.size();i++){
if(s[i]==' '|| i==s.size()){
reverse(s.begin()+a,s.begin()+i);a=i+1;
}
}
return s;
}
};
右旋字符串
通过整体倒序,把两段子串顺序颠倒,两个段子串里的的字符在倒叙一把,负负得正
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
string s;
cin >> n;
cin >> s;
int len = s.size();
reverse(s.begin(), s.end());
reverse(s.begin(), s.begin() + n);
reverse(s.begin() + n, s.end());
cout << s << endl;
}
3.二叉树
二叉树是一种基础数据结构,也是众多数据结构的基石。
二叉树的递归遍历
力扣 144 二叉树的前序遍历
二叉树的前序遍历是按照中左右的顺序来处理的
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void t(TreeNode *cur,vector <int> &vec){
if(cur == NULL) return;
vec.push_back(cur->val);
t(cur->left,vec);
t(cur->right,vec);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
t(root,result);
return result;
}
};
力扣 94 二叉树的中序遍历
二叉树的中序遍历是按照左中右的顺序来处理的
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void t(TreeNode *cur,vector<int>&vec){
if(cur==NULL) return;
t(cur->left,vec);
vec.push_back(cur->val);
t(cur->right,vec);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int>result;
t(root,result);
return result;
}
};
力扣 145 二叉树的后序遍历
二叉树的后序遍历是按照左右中的顺序来处理的
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void t(TreeNode *cur,vector<int>&vec){
if(cur==NULL) return;
t(cur->left,vec);
t(cur->right,vec);
vec.push_back(cur->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
t(root,res);
return res;
}
};
力扣 102.二叉树的层序遍历
需要用辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>>result;
queue<TreeNode *>queue;
if(root!=NULL)queue.push(root);
while(!queue.empty()){
vector<int>vec;
int size=queue.size();
while(size--){
TreeNode *node=queue.front();
queue.pop();
vec.push_back(node->val);
if(node->left!=NULL) queue.push(node->left);
if(node->right!=NULL) queue.push(node->right);
}
result.push_back(vec);
}
return result;
}
};
力扣 429.N叉树的层序遍历
这道题一个节点有多个孩子
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> children;
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public:
vector<vector<int>> levelOrder(Node* root) {
vector<vector<int>>result;
queue<Node *>queue;
if(root!=NULL)queue.push(root);
while(!queue.empty()){
vector<int>vec;
int size=queue.size();
while(size--){
Node *node=queue.front();
queue.pop();
vec.push_back(node->val);
for(int i=0;i<node->children.size();i++){
if(node->children[i]) queue.push(node->children[i]);
}
}
result.push_back(vec);
}
return result;
}
};
力扣 104.二叉树的最大深度
可以使用二叉树层序遍历来解决
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode* root) {
queue<TreeNode*> que;
if (root != NULL) que.push(root);
int result=0;
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result++;
}
return result;
}
};
力扣 226.翻转二叉树
使用前序遍历每一个节点的左右孩子交换一下
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(root==NULL) return root;
swap(root->left,root->right);
invertTree(root->left);
invertTree(root->right);
return root;
}
};
力扣 101. 对称二叉树
本题遍历只能是后序遍历,比较的是两个子树的里侧和外侧的元素是否相等
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool t(TreeNode *left,TreeNode *right){
if(left==NULL&&right!=NULL) return false;
else if(left!=NULL&&right==NULL) return false;
else if(left==NULL&&right==NULL) return true;
else if(left->val!=right->val) return false;
bool a=t(left->left,right->right);
bool b=t(left->right,right->left);
bool c;
return c=a&&b;
}
bool isSymmetric(TreeNode* root) {
if(root==NULL) return true;
return t(root->left,root->right);
}
};