哈希表+字符串+二叉树

文章详细介绍了哈希表在解决字符串处理、数组操作、二叉树遍历等问题中的应用,如字母异位词判断、数组交集、快乐数计算、两数之和、赎金信验证以及字符串反转等LeetCode题目。同时讨论了二叉树的前序、中序、后序和层序遍历方法。
摘要由CSDN通过智能技术生成

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);
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值